Skip to content

release: 0.2.0#2

Open
stainless-app[bot] wants to merge 35 commits intomainfrom
release-please--branches--main--changes--next
Open

release: 0.2.0#2
stainless-app[bot] wants to merge 35 commits intomainfrom
release-please--branches--main--changes--next

Conversation

@stainless-app
Copy link
Copy Markdown
Contributor

@stainless-app stainless-app Bot commented Apr 3, 2026

Automated Release PR

0.2.0 (2026-04-23)

Full Changelog: v0.1.0...v0.2.0

Features

  • allow - as value representing stdin to binary-only file parameters in CLIs (40329ac)
  • api: api update (6ea47ba)
  • api: api update (05fc238)
  • api: api update (2f69100)
  • api: api update (07389a5)
  • better error message if scheme forgotten in CLI *_BASE_URL/--base-url (665e431)
  • cli: add --raw-output/-r option to print raw (non-JSON) strings (4222549)
  • cli: alias parameters in data with x-stainless-cli-data-alias (fc1ebc7)
  • cli: send filename and content type when reading input from files (4b76c79)

Bug Fixes

  • cli: fix incompatible Go types for flag generated as array of maps (a95a486)
  • fall back to main branch if linking fails in CI (28b2498)
  • fix for failing to drop invalid module replace in link script (ad3cbf1)
  • fix quoting typo (d4f3537)

Chores

  • add documentation for ./scripts/link (2586047)
  • ci: support manually triggering release workflow (b5836aa)
  • cli: additional test cases for ShowJSONIterator (5784e71)
  • cli: fall back to JSON when using default "explore" with non-TTY (1b5c7e9)
  • cli: let --format raw be used in conjunction with --transform (d9c0c77)
  • cli: switch long lists of positional args over to param structs (4a9e250)
  • cli: use ShowJSONOpts as argument to formatJSON instead of many positionals (9e0c109)
  • internal: more robust bootstrap script (014bf27)
  • mark all CLI-related tests in Go with t.Parallel() (5fc2402)
  • modify CLI tests to inject stdout so mutating os.Stdout isn't necessary (b7fd553)
  • switch some CLI Go tests from os.Chdir to t.Chdir (2f49e45)
  • tests: bump steady to v0.22.1 (522092e)

Documentation


This pull request is managed by Stainless's GitHub App.

The semver version number is based on included commit messages. Alternatively, you can manually set the version number in the title of this pull request.

For a better experience, it is recommended to use either rebase-merge or squash-merge when merging this pull request.

🔗 Stainless website
📚 Read the docs
🙋 Reach out for help or questions

@stainless-app stainless-app Bot force-pushed the release-please--branches--main--changes--next branch from e9ea7d3 to 27e3edd Compare April 3, 2026 05:40
@stainless-app stainless-app Bot force-pushed the release-please--branches--main--changes--next branch from 27e3edd to 25aedf0 Compare April 3, 2026 05:40
@entelligence-ai-pr-reviews
Copy link
Copy Markdown


Confidence Score: 5/5 - Safe to Merge

Safe to merge — this release PR for version 0.2.0 appears clean with no issues identified across the reviewed files. The automated review found no logic bugs, security concerns, or correctness problems in any of the 6 reviewed changed files. This looks like a straightforward version bump or release packaging PR with no substantive technical concerns raised.

Key Findings:

  • No review comments were generated across 6 of 7 changed files, indicating the code changes are clean and well-structured.
  • Zero critical, significant, or medium-severity issues were detected by heuristic analysis, suggesting the release changes are safe.
  • The PR is scoped as a release (0.2.0), which typically involves version metadata updates and changelog entries — low-risk changes by nature.

@stainless-app stainless-app Bot force-pushed the release-please--branches--main--changes--next branch from 25aedf0 to 03c6c45 Compare April 3, 2026 05:41
@stainless-app
Copy link
Copy Markdown
Contributor Author

stainless-app Bot commented Apr 3, 2026

🧪 Testing

To try out this version of the SDK:

Download and unzip: 'https://pkg.stainless.com/s/hyperspell-cli/014bf271f51526dab8ae459bd514bab798c8062d/dist.zip'. On macOS, run 'xattr -d com.apple.quarantine {executable name}'.

Expires at: Sat, 23 May 2026 04:09:24 GMT
Updated at: Thu, 23 Apr 2026 04:09:24 GMT

@canaries-inc
Copy link
Copy Markdown

canaries-inc Bot commented Apr 3, 2026

🐤 Canary Summary

This PR enhances CLI error messaging for base URL configuration:

  • Added upfront validation for HYPERSPELL_BASE_URL environment variable and --base-url flag
  • Users now get clear error messages specifying which configuration source is missing the scheme
  • Validation happens before CLI app execution, catching misconfiguration early
  • Error messages explicitly state expected format (http:// or https://), improving troubleshooting experience

Affected User Flows

Component User Flows
CLI Base URL Validation Improved
Configure API endpoint via env var: Generic URL parse errors → clear message 'HYPERSPELL_BASE_URL "example.com" is missing a scheme (expected http:// or https://)'

Configure API endpoint via CLI flag: Runtime URL errors → immediate validation error '--base-url "localhost:8080" is missing a scheme (expected http:// or https://)'

Start CLI with invalid base URL: App crashes with cryptic errors → early exit with actionable error message before app initialization

@entelligence-ai-pr-reviews
Copy link
Copy Markdown


Confidence Score: 5/5 - Safe to Merge

Safe to merge — this PR cleanly delivers the 0.2.0 release with well-scoped additions including ValidateBaseURL in pkg/cmd/cmdutil.go, onceStdinReader in pkg/cmd/flagoptions.go for safe stdin consumption, and proper wiring of URL validation in both the CLI flag layer (pkg/cmd/cmd.go) and the environment variable path (cmd/hyperspell/main.go). No review comments were generated across the 8 reviewed changed files, and the heuristic analysis found zero critical, significant, or medium issues. The changes are logically coherent — validating the base URL at both the flag and env-var entry points is a sound defensive pattern, and the once-reader abstraction prevents double-consumption of stdin, which is a common correctness concern in CLI tools.

Key Findings:

  • ValidateBaseURL correctly enforces http:///https:// scheme at both the --base-url flag validation site and the HYPERSPELL_BASE_URL environment variable startup path, closing two distinct injection surfaces consistently.
  • onceStdinReader in pkg/cmd/flagoptions.go addresses the classic stdin double-read hazard in CLI pipelines — safe and idiomatic use of sync.Once or equivalent guard for this pattern.
  • All 8 reviewed files produced zero findings from both automated heuristics and manual review comments, indicating the implementation is clean and the PR scope is well-contained to the stated feature set.
Files requiring special attention
  • pkg/cmd/cmdutil.go
  • pkg/cmd/flagoptions.go
  • cmd/hyperspell/main.go

@canaries-inc
Copy link
Copy Markdown

canaries-inc Bot commented Apr 3, 2026

🐤 Canary Proposed Tests

No testable user journeys found for this PR.

@entelligence-ai-pr-reviews
Copy link
Copy Markdown


Confidence Score: 4/5 - Mostly Safe

Safe to merge — this PR introduces well-scoped features including onceStdinReader for enforcing single stdin consumption, isStdinPath() for detecting stdin aliases (-, /dev/fd/0, /dev/stdin), and ValidateBaseURL for HTTP/HTTPS scheme validation in cmdutil.go. The implementation addresses a clear need for binary file parameter support via stdin and tightens base URL validation across the CLI surface. No review comments were generated and all heuristic checks passed cleanly, making this a low-risk release candidate.

Key Findings:

  • onceStdinReader in pkg/cmd/flagoptions.go correctly enforces single-consumption semantics for stdin, which is a sound defensive pattern preventing silent double-read bugs in flag parsing pipelines.
  • ValidateBaseURL in pkg/cmd/cmdutil.go adds meaningful user-facing validation for scheme correctness (http:///https://), reducing the class of misconfiguration errors that could previously surface as cryptic network failures.
  • The isStdinPath() helper correctly enumerates the common stdin path aliases, though coverage of edge cases like /proc/self/fd/0 is not mentioned — this is a minor gap but not a blocking concern.
  • No automated review issues were flagged and 8 of 9 changed files were reviewed, providing high confidence in the change surface.
Files requiring special attention
  • pkg/cmd/flagoptions.go
  • pkg/cmd/cmdutil.go
  • cmd/hyperspell/main.go

@@ -27,6 +29,8 @@ func TestInnerFlagSet(t *testing.T) {

for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Correctness: Adding t.Parallel() inside the range loop without capturing tt (via tt := tt) causes all parallel subtests to share the same loop variable — in Go < 1.22, by the time the subtests run, tt will hold the last iteration's value, making all tests use identical inputs.

🤖 AI Agent Prompt for Cursor/Windsurf

📋 Copy this prompt to your AI coding assistant (Cursor, Windsurf, etc.) to get help fixing this issue

In file `internal/requestflag/innerflag_test.go`, inside the `for _, tt := range tests` loop in `TestInnerFlagSet`, `t.Parallel()` is called without first capturing the loop variable. For Go versions before 1.22, this causes a data race where all parallel subtests may use the last value of `tt`. Add `tt := tt` immediately before `t.Parallel()` on the line after `t.Run(tt.name, func(t *testing.T) {` to create a per-iteration local copy.

Comment on lines 348 to 393
// Test initialization and setting
t.Run("PreParse initialization", func(t *testing.T) {
t.Parallel()

assert.NoError(t, strFlag.PreParse())
assert.True(t, strFlag.applied)
assert.Equal(t, "default-string", strFlag.Get())
})

t.Run("Set string flag", func(t *testing.T) {
t.Parallel()

assert.NoError(t, strFlag.Set("string-flag", "new-value"))
assert.Equal(t, "new-value", strFlag.Get())
assert.True(t, strFlag.IsSet())
})

t.Run("Set int flag with valid value", func(t *testing.T) {
t.Parallel()

assert.NoError(t, superstitiousIntFlag.Set("int-flag", "100"))
assert.Equal(t, int64(100), superstitiousIntFlag.Get())
assert.True(t, superstitiousIntFlag.IsSet())
})

t.Run("Set int flag with invalid value", func(t *testing.T) {
t.Parallel()

assert.Error(t, superstitiousIntFlag.Set("int-flag", "not-an-int"))
})

t.Run("Set int flag with validator failing", func(t *testing.T) {
t.Parallel()

assert.Error(t, superstitiousIntFlag.Set("int-flag", "13"))
})

t.Run("Set bool flag", func(t *testing.T) {
t.Parallel()

assert.NoError(t, boolFlag.Set("bool-flag", "true"))
assert.Equal(t, true, boolFlag.Get())
assert.True(t, boolFlag.IsSet())
})

t.Run("Set slice flag with multiple values", func(t *testing.T) {
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Correctness: Adding t.Parallel() to these subtests while they all share the same strFlag, superstitiousIntFlag, and boolFlag instances (defined in the outer TestFlagSet scope) introduces data races — concurrent calls to PreParse, Set, and Get on the same flag objects will race under -race, causing flaky or incorrect test results.

🤖 AI Agent Prompt for Cursor/Windsurf

📋 Copy this prompt to your AI coding assistant (Cursor, Windsurf, etc.) to get help fixing this issue

In `internal/requestflag/requestflag_test.go`, the diff adds `t.Parallel()` to subtests inside `TestFlagSet` (around lines 347–393). However, those subtests all operate on the same shared `strFlag`, `superstitiousIntFlag`, and `boolFlag` variables declared in the outer test function. Running them in parallel causes concurrent reads and writes to those shared `Flag` structs, which is a data race.

Fix: Either (a) remove `t.Parallel()` from the subtests that share these outer-scope flag variables, or (b) move the flag construction inside each subtest so each parallel subtest has its own independent instance. The subtests at the bottom of `TestFlagSet` that already create local `sliceFlag` variables are safe to keep parallel.

@entelligence-ai-pr-reviews
Copy link
Copy Markdown


Confidence Score: 3/5 - Review Recommended

Not safe to merge without fixes — while this PR delivers meaningful improvements like ValidateBaseURL, onceStdinReader, and startup validation in main.go, the test suite changes introduce two concrete correctness bugs that undermine the value of the new tests. Specifically, innerflag_test.go adds t.Parallel() inside a range loop without capturing the loop variable tt := tt, meaning all parallel subtests will use the last iteration's value in Go < 1.22. Additionally, requestflag_test.go runs parallel subtests that share mutable flag instances (strFlag, superstitiousIntFlag, boolFlag) defined in the outer TestFlagSet scope, introducing data races under -race that will cause non-deterministic failures.

Key Findings:

  • In internal/requestflag/innerflag_test.go, t.Parallel() is called inside a range loop without tt := tt variable capture — in Go < 1.22, all parallel subtests will reference the same final loop value, making the tests effectively useless as they all run with identical (last) inputs.
  • In internal/requestflag/requestflag_test.go, parallel subtests share the same outer-scope strFlag, superstitiousIntFlag, and boolFlag instances and concurrently call PreParse, Set, and Get on them — this is a real data race detectable with go test -race and can cause intermittent test failures or undefined behavior.
  • The production-side changes (ValidateBaseURL, onceStdinReader, startup exit-code validation) appear well-structured and purposeful, so the PR's core feature work is sound — only the test infrastructure is broken.
  • Both test bugs are in the same package and were introduced together as part of parallelizing the test suite, suggesting a systematic oversight when adding t.Parallel() calls without auditing shared state.
Files requiring special attention
  • internal/requestflag/innerflag_test.go
  • internal/requestflag/requestflag_test.go

@stainless-app stainless-app Bot force-pushed the release-please--branches--main--changes--next branch from 03c6c45 to 5683b46 Compare April 3, 2026 21:30
@stainless-app stainless-app Bot force-pushed the release-please--branches--main--changes--next branch from 5683b46 to 373f189 Compare April 4, 2026 05:08
Comment on lines 348 to 398
// Test initialization and setting
t.Run("PreParse initialization", func(t *testing.T) {
t.Parallel()

assert.NoError(t, strFlag.PreParse())
assert.True(t, strFlag.applied)
assert.Equal(t, "default-string", strFlag.Get())
})

t.Run("Set string flag", func(t *testing.T) {
t.Parallel()

assert.NoError(t, strFlag.Set("string-flag", "new-value"))
assert.Equal(t, "new-value", strFlag.Get())
assert.True(t, strFlag.IsSet())
})

t.Run("Set int flag with valid value", func(t *testing.T) {
t.Parallel()

assert.NoError(t, superstitiousIntFlag.Set("int-flag", "100"))
assert.Equal(t, int64(100), superstitiousIntFlag.Get())
assert.True(t, superstitiousIntFlag.IsSet())
})

t.Run("Set int flag with invalid value", func(t *testing.T) {
t.Parallel()

assert.Error(t, superstitiousIntFlag.Set("int-flag", "not-an-int"))
})

t.Run("Set int flag with validator failing", func(t *testing.T) {
t.Parallel()

assert.Error(t, superstitiousIntFlag.Set("int-flag", "13"))
})

t.Run("Set bool flag", func(t *testing.T) {
t.Parallel()

assert.NoError(t, boolFlag.Set("bool-flag", "true"))
assert.Equal(t, true, boolFlag.Get())
assert.True(t, boolFlag.IsSet())
})

t.Run("Set slice flag with multiple values", func(t *testing.T) {
t.Parallel()

sliceFlag := &Flag[[]int64]{
Name: "slice-flag",
Default: []int64{},
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Correctness: The subtests now run in parallel but all mutate shared strFlag, superstitiousIntFlag, and boolFlag declared in the outer TestFlagSet scope — this introduces data races on Flag internal fields (value, hasBeenSet, applied, count) with no synchronization, causing non-deterministic test failures and potential panics.

🤖 AI Agent Prompt for Cursor/Windsurf

📋 Copy this prompt to your AI coding assistant (Cursor, Windsurf, etc.) to get help fixing this issue

In file `internal/requestflag/requestflag_test.go`, the `t.Parallel()` calls added to subtests inside `TestFlagSet` (starting around line 348) cause data races because `strFlag`, `superstitiousIntFlag`, and `boolFlag` are shared mutable state across parallel subtests. Fix this by either: (1) removing `t.Parallel()` from all subtests that share these outer-scope flag variables, or (2) moving the flag declarations inside each subtest so each parallel subtest operates on its own independent flag instance.

Comment thread pkg/cmd/memory.go Outdated
Comment on lines 375 to 379
Usage: "The file to ingest.",
Required: true,
BodyPath: "file",
},
&requestflag.Flag[any]{
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Correctness: Removing FileInput: true means the requestflag package will no longer treat this flag as a file path to read and stream — it will pass the raw string value (the filename) as the body instead of the file contents, silently breaking the upload endpoint.

🤖 AI Agent Prompt for Cursor/Windsurf

📋 Copy this prompt to your AI coding assistant (Cursor, Windsurf, etc.) to get help fixing this issue

In pkg/cmd/memory.go around line 375, the `FileInput: true` field was removed from the `requestflag.Flag[string]` struct for the 'file' flag in the `memoriesUpload` command. This field is required for the requestflag package to read the actual file contents from the provided path and pass them to the multipart form upload. Without it, only the raw filename string is sent as the body, breaking file uploads silently. Restore `FileInput: true` to the flag definition.

@@ -114,6 +116,8 @@ func TestEncode(t *testing.T) {

for name, test := range tests {
t.Run(name, func(t *testing.T) {
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Correctness: Adding t.Parallel() inside the range loop without capturing name and test per iteration causes all subtests to close over the same loop variables — in Go < 1.22 they will all run with the last iteration's values, producing incorrect/flaky test results.

Affected Locations:

  • internal/apiquery/query_test.go:118-118
  • internal/requestflag/innerflag_test.go:31-31
  • internal/requestflag/requestflag_test.go:60-61
🤖 AI Agent Prompt for Cursor/Windsurf

📋 Copy this prompt to your AI coding assistant (Cursor, Windsurf, etc.) to get help fixing this issue

In internal/apiquery/query_test.go, around line 116-117, the for-range loop over `tests` was given a `t.Parallel()` call inside the `t.Run` callback. Without capturing the loop variables locally, all parallel subtests will share the same `name` and `test` variables (the last iteration's values in Go < 1.22), causing incorrect test behaviour. Add `name, test := name, test` immediately after the `t.Run` open brace (before `t.Parallel()`) to shadow and capture each iteration's values.

@entelligence-ai-pr-reviews
Copy link
Copy Markdown


Confidence Score: 1/5 - Blocking Issues

Not safe to merge — this PR introduces multiple correctness-breaking bugs that will cause non-deterministic test failures and a silent functional regression in production. In internal/requestflag/requestflag_test.go, subtests now run in parallel while mutating shared strFlag, superstitiousIntFlag, and boolFlag instances declared in the outer TestFlagSet scope, creating data races on Flag internal fields. In pkg/cmd/memory.go, removing FileInput: true silently breaks the upload endpoint by passing a raw filename string as the request body instead of streaming the file contents. Additionally, internal/apiquery/query_test.go adds t.Parallel() inside a range loop without capturing loop variables, causing all subtests to close over the last iteration's values in Go < 1.22 — a pre-existing version of this same loop-variable closure bug in internal/requestflag/innerflag_test.go also remains unresolved from a prior review, indicating a pattern of unsafe parallel test refactoring throughout the codebase.

Key Findings:

  • In pkg/cmd/memory.go, removing FileInput: true from the flag options means the requestflag package will pass the raw filename string as the HTTP body instead of reading and streaming the file contents — this silently breaks the upload endpoint with no error surfaced to the user.
  • In internal/requestflag/requestflag_test.go, parallel subtests all mutate the shared strFlag, superstitiousIntFlag, and boolFlag variables from the outer TestFlagSet scope without synchronization, introducing data races on Flag internal fields (value, hasBeenSet, applied, count) that will cause non-deterministic and flaky test results.
  • In internal/apiquery/query_test.go, t.Parallel() is called inside a range loop without capturing name and test per iteration — in Go versions below 1.22 all parallel subtests will close over the final loop variable values, producing incorrect test behavior; this same anti-pattern also remains unresolved in internal/requestflag/innerflag_test.go from a prior review.
  • The PR does deliver meaningful improvements — ValidateBaseURL enforcement at startup, io.Writer abstraction in writeBinaryResponse for testability, and stdin file input support are all well-motivated changes — but the functional regression in memory.go and the data-race bugs in the test suite make the PR unsafe to merge in its current state.
Files requiring special attention
  • pkg/cmd/memory.go
  • internal/requestflag/requestflag_test.go
  • internal/apiquery/query_test.go
  • internal/requestflag/innerflag_test.go

@stainless-app stainless-app Bot force-pushed the release-please--branches--main--changes--next branch from 373f189 to b0b376a Compare April 7, 2026 08:10
@stainless-app stainless-app Bot force-pushed the release-please--branches--main--changes--next branch from b0b376a to 4d95a0b Compare April 7, 2026 08:11
Comment on lines 348 to 392
// Test initialization and setting
t.Run("PreParse initialization", func(t *testing.T) {
t.Parallel()

assert.NoError(t, strFlag.PreParse())
assert.True(t, strFlag.applied)
assert.Equal(t, "default-string", strFlag.Get())
})

t.Run("Set string flag", func(t *testing.T) {
t.Parallel()

assert.NoError(t, strFlag.Set("string-flag", "new-value"))
assert.Equal(t, "new-value", strFlag.Get())
assert.True(t, strFlag.IsSet())
})

t.Run("Set int flag with valid value", func(t *testing.T) {
t.Parallel()

assert.NoError(t, superstitiousIntFlag.Set("int-flag", "100"))
assert.Equal(t, int64(100), superstitiousIntFlag.Get())
assert.True(t, superstitiousIntFlag.IsSet())
})

t.Run("Set int flag with invalid value", func(t *testing.T) {
t.Parallel()

assert.Error(t, superstitiousIntFlag.Set("int-flag", "not-an-int"))
})

t.Run("Set int flag with validator failing", func(t *testing.T) {
t.Parallel()

assert.Error(t, superstitiousIntFlag.Set("int-flag", "13"))
})

t.Run("Set bool flag", func(t *testing.T) {
t.Parallel()

assert.NoError(t, boolFlag.Set("bool-flag", "true"))
assert.Equal(t, true, boolFlag.Get())
assert.True(t, boolFlag.IsSet())
})

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Correctness: All subtests now run in parallel but share the same strFlag, superstitiousIntFlag, and boolFlag instances defined in the outer scope — concurrent reads and writes to their internal mutable fields (value, hasBeenSet, applied, count) will cause data races detected by go test -race and produce non-deterministic results.

🤖 AI Agent Prompt for Cursor/Windsurf

📋 Copy this prompt to your AI coding assistant (Cursor, Windsurf, etc.) to get help fixing this issue

In `internal/requestflag/requestflag_test.go`, the subtests inside `TestFlagSet` (starting around line 347) were made parallel via `t.Parallel()`, but they all share the same `strFlag`, `superstitiousIntFlag`, and `boolFlag` variables declared in the outer function scope. These `Flag` structs have mutable fields (`value`, `hasBeenSet`, `applied`, `count`) that are written concurrently, causing data races. Fix this by either: (1) removing `t.Parallel()` from subtests that share these outer variables, or (2) moving the flag construction inside each subtest so each parallel subtest has its own local instance.

Comment thread pkg/cmd/flagoptions_test.go
Comment thread pkg/cmd/memory.go
Comment on lines 371 to 380
Suggest: true,
Flags: []cli.Flag{
&requestflag.Flag[string]{
Name: "file",
Usage: "The file to ingest.",
Required: true,
BodyPath: "file",
FileInput: true,
Name: "file",
Usage: "The file to ingest.",
Required: true,
BodyPath: "file",
},
&requestflag.Flag[any]{
Name: "collection",
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Correctness: The FileInput: true field has been removed from the file flag, which likely means the CLI will pass the raw string (file path) instead of reading and streaming the file contents for multipart upload — breaking the memories upload command.

🤖 AI Agent Prompt for Cursor/Windsurf

📋 Copy this prompt to your AI coding assistant (Cursor, Windsurf, etc.) to get help fixing this issue

In pkg/cmd/memory.go around line 371-380, the `FileInput: true` field was removed from the `requestflag.Flag[string]` definition for the 'file' flag in the `memoriesUpload` command. This field is required so the CLI reads the file from disk and passes its contents (not just the path string) to the multipart form upload. Restore `FileInput: true` to the flag definition to fix the upload functionality.

@entelligence-ai-pr-reviews
Copy link
Copy Markdown


Confidence Score: 2/5 - Changes Needed

Not safe to merge — this PR introduces three high-severity bugs that must be addressed before merging. In pkg/cmd/flagoptions_test.go, parallel subtests iterate over tt without capturing it, meaning all subtests run with the final loop value in Go < 1.22, making the entire parallel test suite unreliable. In internal/requestflag/requestflag_test.go, shared mutable flag instances (strFlag, superstitiousIntFlag, boolFlag) are accessed concurrently across parallel subtests, introducing data races that go test -race will catch — and this concern has been flagged in two prior unresolved review comments. Most critically, the removal of FileInput: true from the file flag in pkg/cmd/memory.go likely breaks the memories upload command by passing a raw file path string instead of streaming file contents to the multipart upload. The PR's goals — stdin support for @file parameters, ValidateBaseURL enforcement, and test modernization — are well-intentioned, but these regressions block a safe release.

Key Findings:

  • In pkg/cmd/flagoptions_test.go, the for _, tt := range tests loop adds t.Parallel() without a tt := tt capture, causing all parallel subtests to close over the same loop variable and execute with only the last test case's data in Go versions prior to 1.22.
  • In internal/requestflag/requestflag_test.go, strFlag, superstitiousIntFlag, and boolFlag are declared once in the outer TestFlagSet scope and then mutated concurrently by multiple t.Parallel() subtests, introducing data races on internal fields like value, hasBeenSet, applied, and count — this was flagged in two prior unresolved review comments and remains unaddressed.
  • In pkg/cmd/memory.go, removing FileInput: true from the file flag definition means the flag no longer signals that it should read and stream file contents; the CLI will instead forward the raw path string to the multipart upload, functionally breaking the memories upload command.
  • The test modernization effort (widespread t.Parallel() adoption) is a positive direction, but the incorrect parallel patterns introduced here undermine test reliability precisely in the areas being modernized.
  • 3 previous unresolved comment(s) likely resolved in latest diff (score-only signal; thread status unchanged)
Files requiring special attention
  • pkg/cmd/memory.go
  • pkg/cmd/flagoptions_test.go
  • internal/requestflag/requestflag_test.go

@@ -114,6 +116,8 @@ func TestEncode(t *testing.T) {

for name, test := range tests {
t.Run(name, func(t *testing.T) {
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Correctness: Adding t.Parallel() inside the subtest causes the closure to capture the test loop variable by reference; in Go < 1.22 all parallel subtests will race on the same test value, producing incorrect or flaky results. A local copy (test := test) is needed before t.Parallel() to pin the value per iteration.

🤖 AI Agent Prompt for Cursor/Windsurf

📋 Copy this prompt to your AI coding assistant (Cursor, Windsurf, etc.) to get help fixing this issue

In internal/apiquery/query_test.go, around line 118, the subtest closure added `t.Parallel()` but the `test` loop variable is captured by reference. In Go versions before 1.22, all parallel subtests will share the same loop variable, causing data races and incorrect test behavior. Fix by adding `test := test` immediately before `t.Parallel()` inside the closure to create a per-iteration copy of the loop variable.

Comment on lines 348 to +386
// Test initialization and setting
t.Run("PreParse initialization", func(t *testing.T) {
t.Parallel()

assert.NoError(t, strFlag.PreParse())
assert.True(t, strFlag.applied)
assert.Equal(t, "default-string", strFlag.Get())
})

t.Run("Set string flag", func(t *testing.T) {
t.Parallel()

assert.NoError(t, strFlag.Set("string-flag", "new-value"))
assert.Equal(t, "new-value", strFlag.Get())
assert.True(t, strFlag.IsSet())
})

t.Run("Set int flag with valid value", func(t *testing.T) {
t.Parallel()

assert.NoError(t, superstitiousIntFlag.Set("int-flag", "100"))
assert.Equal(t, int64(100), superstitiousIntFlag.Get())
assert.True(t, superstitiousIntFlag.IsSet())
})

t.Run("Set int flag with invalid value", func(t *testing.T) {
t.Parallel()

assert.Error(t, superstitiousIntFlag.Set("int-flag", "not-an-int"))
})

t.Run("Set int flag with validator failing", func(t *testing.T) {
t.Parallel()

assert.Error(t, superstitiousIntFlag.Set("int-flag", "13"))
})

t.Run("Set bool flag", func(t *testing.T) {
t.Parallel()
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Correctness: The subtests PreParse initialization, Set string flag, Set int flag with valid value, Set int flag with invalid value, Set int flag with validator failing, and Set bool flag all share the same strFlag, superstitiousIntFlag, and boolFlag pointers declared in the outer TestFlagSet scope. Adding t.Parallel() to these subtests causes concurrent reads and writes to those shared flag structs (mutating value, hasBeenSet, applied, count), introducing data races that will produce non-deterministic failures or corrupt state under -race.

🤖 AI Agent Prompt for Cursor/Windsurf

📋 Copy this prompt to your AI coding assistant (Cursor, Windsurf, etc.) to get help fixing this issue

In `internal/requestflag/requestflag_test.go`, the subtests inside `TestFlagSet` that were made parallel (lines ~348-386) all mutate shared flag instances (`strFlag`, `superstitiousIntFlag`, `boolFlag`) declared in the outer function scope. This creates data races. Fix this by either: (1) removing `t.Parallel()` from all subtests that share these outer-scope flag variables, or (2) constructing a fresh flag instance inside each subtest instead of sharing the outer-scope ones. The 'Set slice flag' subtests are fine since they already create local flags.

Comment thread pkg/cmd/memory.go
Comment on lines 371 to 380
Suggest: true,
Flags: []cli.Flag{
&requestflag.Flag[string]{
Name: "file",
Usage: "The file to ingest.",
Required: true,
BodyPath: "file",
FileInput: true,
Name: "file",
Usage: "The file to ingest.",
Required: true,
BodyPath: "file",
},
&requestflag.Flag[any]{
Name: "collection",
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Correctness: Removing FileInput: true means the file flag will no longer be treated as a file path to open and read — it will be passed as a raw string, causing multipart uploads to send the filename string instead of the actual file contents.

🤖 AI Agent Prompt for Cursor/Windsurf

📋 Copy this prompt to your AI coding assistant (Cursor, Windsurf, etc.) to get help fixing this issue

In pkg/cmd/memory.go around line 371-380, the `FileInput: true` field was removed from the `requestflag.Flag[string]` definition for the 'file' flag in the `memoriesUpload` command. This field is responsible for instructing the flag processing logic to open the file at the given path and read its contents for multipart upload. Without it, the flag value is treated as a plain string (the filename), not the actual file data, breaking file uploads. Please restore `FileInput: true` to this flag definition.

@entelligence-ai-pr-reviews
Copy link
Copy Markdown


Confidence Score: 1/5 - Blocking Issues

Not safe to merge — this PR introduces data races in parallelized test suites and a functional regression in multipart file uploads. In internal/requestflag/requestflag_test.go, multiple subtests running in parallel all mutate shared strFlag, superstitiousIntFlag, and boolFlag instances declared in the outer TestFlagSet scope, producing concurrent read/write races that will cause flaky or incorrect test results — and this concern has been raised in three separate unresolved prior review comments, meaning it has been flagged repeatedly without correction. In internal/apiquery/query_test.go, the loop-variable capture bug (missing test := test before t.Parallel()) will cause all parallel subtests to reference the same final loop value in Go < 1.22. Most critically, the removal of FileInput: true from the file flag in pkg/cmd/memory.go is a behavioral regression that will cause multipart uploads to send the literal filename string rather than the actual file contents, breaking the feature the PR claims to enhance.

Key Findings:

  • In pkg/cmd/memory.go, removing FileInput: true from the file flag definition means the flag is no longer treated as a path to open — multipart uploads will transmit the raw filename string as the body, not the file contents, which is a silent functional regression for all binary file parameter uploads.
  • In internal/requestflag/requestflag_test.go, the parallel subtests Set string flag, Set int flag with valid value, Set int flag with invalid value, etc. all concurrently mutate the same strFlag, superstitiousIntFlag, and boolFlag pointers from the outer scope, introducing data races; this issue has appeared in three consecutive unresolved review comments and remains unfixed.
  • In internal/apiquery/query_test.go, the table-driven subtests call t.Parallel() without a local copy of the test loop variable, so in Go versions before 1.22 every goroutine captures the same final iteration value, rendering the parallel subtests useless for correctness and potentially masking real failures.
  • The combination of a functional file-upload regression (FileInput removal) and multiple confirmed data races in the newly parallelized test suites means neither the production code nor the test harness can be trusted as-is.
  • 4 previous unresolved comment(s) likely resolved in latest diff (score-only signal; thread status unchanged)
Files requiring special attention
  • pkg/cmd/memory.go
  • internal/requestflag/requestflag_test.go
  • internal/apiquery/query_test.go

@entelligence-ai-pr-reviews
Copy link
Copy Markdown


Confidence Score: 2/5 - Changes Needed

Not safe to merge — this PR introduces multiple concrete correctness bugs that will cause non-deterministic test failures and logic errors in production code. Specifically, requestflag_test.go runs six subtests in parallel while sharing mutable strFlag, superstitiousIntFlag, and boolFlag instances from the outer scope, creating a data race; innerflag_test.go adds t.Parallel() without pinning tt := tt, causing all subtests to observe the final loop value on Go < 1.22; and cmdutil.go's ShowJSON applies opts.Transform up to three times — once at the top of the function, once in the recursive fallback call, and once inside formatJSON — producing corrupted output for any caller that provides a transform. These bugs are not pre-existing; they are introduced or directly enabled by changes in this PR, and the pattern of unpinned loop variables with t.Parallel() recurs across at least three additional test files (apiform/form_test.go, apiquery/query_test.go) whose unresolved comments have been open since earlier reviews.

Key Findings:

  • In requestflag_test.go (L347-L398), the six parallel subtests concurrently mutate and read strFlag, superstitiousIntFlag, and boolFlag declared in the enclosing TestFlagSet scope — this is a textbook data race that will produce non-deterministic failures and is caught by go test -race.
  • In innerflag_test.go (L29-L36), t.Parallel() is called inside a range loop without tt := tt to shadow the loop variable; on Go < 1.22 every subtest body runs after the loop completes, so all assertions execute against the final iteration's tt value, making the entire test suite meaningless.
  • In cmdutil.go, ShowJSON mutates res via opts.Transform at the top of the function, then passes opts (still carrying Transform) into recursive ShowJSON calls for the auto/explore fallbacks, and formatJSON applies the transform yet again — resulting in double- or triple-application of the transform for non-explicit-format paths, silently corrupting output.
  • The unpinned-loop-variable + t.Parallel() pattern also appears unresolved in apiform/form_test.go and apiquery/query_test.go with over 20 repeated review comments across prior review rounds, indicating these issues have been flagged but not addressed before this release cut.
Files requiring special attention
  • pkg/cmd/cmdutil.go
  • internal/requestflag/requestflag_test.go
  • internal/requestflag/innerflag_test.go
  • internal/apiform/form_test.go
  • internal/apiquery/query_test.go

Comment on lines 348 to 392
// Test initialization and setting
t.Run("PreParse initialization", func(t *testing.T) {
t.Parallel()

assert.NoError(t, strFlag.PreParse())
assert.True(t, strFlag.applied)
assert.Equal(t, "default-string", strFlag.Get())
})

t.Run("Set string flag", func(t *testing.T) {
t.Parallel()

assert.NoError(t, strFlag.Set("string-flag", "new-value"))
assert.Equal(t, "new-value", strFlag.Get())
assert.True(t, strFlag.IsSet())
})

t.Run("Set int flag with valid value", func(t *testing.T) {
t.Parallel()

assert.NoError(t, superstitiousIntFlag.Set("int-flag", "100"))
assert.Equal(t, int64(100), superstitiousIntFlag.Get())
assert.True(t, superstitiousIntFlag.IsSet())
})

t.Run("Set int flag with invalid value", func(t *testing.T) {
t.Parallel()

assert.Error(t, superstitiousIntFlag.Set("int-flag", "not-an-int"))
})

t.Run("Set int flag with validator failing", func(t *testing.T) {
t.Parallel()

assert.Error(t, superstitiousIntFlag.Set("int-flag", "13"))
})

t.Run("Set bool flag", func(t *testing.T) {
t.Parallel()

assert.NoError(t, boolFlag.Set("bool-flag", "true"))
assert.Equal(t, true, boolFlag.Get())
assert.True(t, boolFlag.IsSet())
})

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Correctness: All six subtests now run in parallel but share the same strFlag, superstitiousIntFlag, and boolFlag pointers declared in the outer TestFlagSet scope — concurrent reads and writes to their internal value, hasBeenSet, applied, and count fields will cause data races and non-deterministic assertions (e.g. strFlag.Get() in "PreParse initialization" may see the value written by "Set string flag" and vice-versa).

🤖 AI Agent Prompt for Cursor/Windsurf

📋 Copy this prompt to your AI coding assistant (Cursor, Windsurf, etc.) to get help fixing this issue

In internal/requestflag/requestflag_test.go, the subtests added in the diff (lines 347-398 of TestFlagSet) all call t.Parallel() but share the mutable flag variables strFlag, superstitiousIntFlag, and boolFlag declared in the outer test function. This introduces data races. Fix by either (a) removing t.Parallel() from every subtest that uses these shared variables, or (b) moving each flag declaration inside its own subtest so there is no shared mutable state.

Comment on lines 222 to 243
for _, tt := range tests {
t.Run(tt.name+" text", func(t *testing.T) {
got, err := embedFiles(tt.input, EmbedText)
t.Parallel()

got, err := embedFiles(tt.input, EmbedText, nil)
if tt.wantErr {
assert.Error(t, err)
require.Error(t, err)
} else {
require.NoError(t, err)
assert.Equal(t, tt.want, got)
require.Equal(t, tt.want, got)
}
})

t.Run(tt.name+" io.Reader", func(t *testing.T) {
_, err := embedFiles(tt.input, EmbedIOReader)
t.Parallel()

_, err := embedFiles(tt.input, EmbedIOReader, nil)
if tt.wantErr {
assert.Error(t, err)
require.Error(t, err)
} else {
require.NoError(t, err)
}
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Correctness: Adding t.Parallel() inside subtests that close over tt from the range loop creates a classic Go loop-variable capture bug in Go < 1.22 — all parallel subtests will likely reference the final value of tt rather than their intended iteration value, causing wrong inputs to be tested and silently passing incorrect assertions.

🤖 AI Agent Prompt for Cursor/Windsurf

📋 Copy this prompt to your AI coding assistant (Cursor, Windsurf, etc.) to get help fixing this issue

In pkg/cmd/flagoptions_test.go, around the for-range loop at line 221, the diff adds t.Parallel() inside subtests that close over the loop variable `tt`. In Go versions before 1.22 this causes all parallel subtests to share the last iteration's `tt` value. Fix this by adding `tt := tt` immediately after the `for _, tt := range tests {` line to shadow and capture the loop variable for each iteration.

@entelligence-ai-pr-reviews
Copy link
Copy Markdown


Confidence Score: 1/5 - Blocking Issues

Not safe to merge — this PR introduces multiple data race conditions across the test suite, most critically in internal/requestflag/requestflag_test.go where six parallel subtests share the same strFlag, superstitiousIntFlag, and boolFlag pointer instances from the outer TestFlagSet scope, causing concurrent reads and writes to their internal state fields. Additionally, pkg/cmd/flagoptions_test.go exhibits the classic Go loop-variable capture bug with t.Parallel() and shared tt in pre-1.22 Go, causing subtests to silently test wrong inputs. While the PR delivers meaningful improvements — stdin support via onceStdinReader, fileUpload struct with MIME metadata, and ShowJSONOpts refactoring — the 43 pre-existing unresolved comments reveal a systemic pattern of the same parallel/loop-variable bug reproduced across internal/apiform/form_test.go, internal/apiquery/query_test.go, and internal/requestflag/innerflag_test.go, none of which have been addressed.

Key Findings:

  • In internal/requestflag/requestflag_test.go lines 347-398, all six t.Run subtests call t.Parallel() while closing over the same strFlag, superstitiousIntFlag, and boolFlag instances declared in the outer test scope — concurrent mutations to their value, hasBeenSet, applied, and count fields will cause data races detectable by go test -race and non-deterministic test outcomes.
  • In pkg/cmd/flagoptions_test.go, t.Parallel() is added inside a range loop that captures tt by reference without the tt := tt pin — in any Go version prior to 1.22 this means all parallel subtests will execute with the final loop iteration's value of tt, silently validating wrong inputs and providing false test coverage.
  • 43 pre-existing unresolved comments document the identical loop-variable capture bug repeated across internal/apiform/form_test.go, internal/apiquery/query_test.go, and internal/requestflag/innerflag_test.go — this pattern has not been addressed across any of these files in the current PR, indicating a systemic issue with how parallelism was introduced into the test suite.
  • The combination of shared mutable state races and loop-variable capture bugs means the test suite gives false confidence: tests may pass non-deterministically while masking real regressions in the refactored ShowJSONOpts, onceStdinReader, and fileUpload code paths.
Files requiring special attention
  • internal/requestflag/requestflag_test.go
  • pkg/cmd/flagoptions_test.go
  • internal/apiform/form_test.go
  • internal/apiquery/query_test.go
  • internal/requestflag/innerflag_test.go

Comment on lines 348 to 393
// Test initialization and setting
t.Run("PreParse initialization", func(t *testing.T) {
t.Parallel()

assert.NoError(t, strFlag.PreParse())
assert.True(t, strFlag.applied)
assert.Equal(t, "default-string", strFlag.Get())
})

t.Run("Set string flag", func(t *testing.T) {
t.Parallel()

assert.NoError(t, strFlag.Set("string-flag", "new-value"))
assert.Equal(t, "new-value", strFlag.Get())
assert.True(t, strFlag.IsSet())
})

t.Run("Set int flag with valid value", func(t *testing.T) {
t.Parallel()

assert.NoError(t, superstitiousIntFlag.Set("int-flag", "100"))
assert.Equal(t, int64(100), superstitiousIntFlag.Get())
assert.True(t, superstitiousIntFlag.IsSet())
})

t.Run("Set int flag with invalid value", func(t *testing.T) {
t.Parallel()

assert.Error(t, superstitiousIntFlag.Set("int-flag", "not-an-int"))
})

t.Run("Set int flag with validator failing", func(t *testing.T) {
t.Parallel()

assert.Error(t, superstitiousIntFlag.Set("int-flag", "13"))
})

t.Run("Set bool flag", func(t *testing.T) {
t.Parallel()

assert.NoError(t, boolFlag.Set("bool-flag", "true"))
assert.Equal(t, true, boolFlag.Get())
assert.True(t, boolFlag.IsSet())
})

t.Run("Set slice flag with multiple values", func(t *testing.T) {
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Correctness: All the parallel subtests share the same strFlag, superstitiousIntFlag, and boolFlag instances declared in the outer TestFlagSet scope — running them concurrently with t.Parallel() introduces data races where one subtest's mutation (e.g. strFlag.Set) races with another's read (e.g. strFlag.Get), causing non-deterministic failures and race detector violations.

🤖 AI Agent Prompt for Cursor/Windsurf

📋 Copy this prompt to your AI coding assistant (Cursor, Windsurf, etc.) to get help fixing this issue

In internal/requestflag/requestflag_test.go, the subtests 'PreParse initialization', 'Set string flag', 'Set int flag with valid value', 'Set int flag with invalid value', 'Set int flag with validator failing', and 'Set bool flag' were made parallel by adding t.Parallel(), but they all share the same strFlag, superstitiousIntFlag, and boolFlag variables declared in the outer TestFlagSet function. This creates data races. Fix this by either: (1) removing t.Parallel() from these subtests since they depend on shared state, or (2) declaring separate flag instances inside each subtest so each has its own isolated state.

Comment thread pkg/cmd/flagoptions_test.go
@@ -114,6 +116,8 @@ func TestEncode(t *testing.T) {

for name, test := range tests {
t.Run(name, func(t *testing.T) {
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Correctness: Adding t.Parallel() here causes the subtests to capture the loop variables name and test by reference — on Go < 1.22, all parallel subtests will run with the last iteration's values, making the tests non-deterministic or silently testing the wrong inputs.

🤖 AI Agent Prompt for Cursor/Windsurf

📋 Copy this prompt to your AI coding assistant (Cursor, Windsurf, etc.) to get help fixing this issue

In file internal/apiquery/query_test.go, at the for-loop starting around line 116, `t.Parallel()` was added inside `t.Run` without re-declaring the loop variables. On Go < 1.22, all parallel subtests will share the same `name` and `test` variables (captured by reference from the outer loop), causing them all to run with the final iteration's values. Fix by adding `name, test := name, test` immediately after the `t.Run(name, func(t *testing.T) {` line and before `t.Parallel()`, so each closure captures its own copy of the loop variables.

@entelligence-ai-pr-reviews
Copy link
Copy Markdown


Confidence Score: 2/5 - Changes Needed

Not safe to merge — this PR introduces widespread data-race and loop-variable-capture bugs across the test suite that will cause non-deterministic test results or silent correctness failures. Specifically, requestflag_test.go's parallel subtests in TestFlagSet share mutable strFlag, superstitiousIntFlag, and boolFlag instances across goroutines, flagoptions_test.go's table-driven parallel subtests close over the uncopied tt loop variable (meaning every subtest runs with the last test case's data), and query_test.go has the same loop-variable-capture bug for name and test on Go < 1.22. While the PR itself delivers meaningful features — --raw-output flag, ShowJSONOpts refactor, stdin support, and improved URL validation — these correctness issues in the test layer are unresolved and have been flagged repeatedly in prior review rounds, indicating they need to be fixed before the test suite can be trusted to gate this release.

Key Findings:

  • In requestflag_test.go, parallel subtests inside TestFlagSet concurrently mutate and read the shared outer-scope strFlag, superstitiousIntFlag, and boolFlag variables, introducing real data races detectable by go test -race and making test outcomes unreliable.
  • In flagoptions_test.go, the for _, tt := range tests loop adds t.Parallel() without a tt := tt capture, so all parallel subtests execute with whichever tt the loop variable holds at scheduling time — almost certainly the last element — silently skipping validation of all other cases.
  • In internal/apiquery/query_test.go (and identically in internal/apiform/form_test.go), t.Parallel() is called inside for name, test := range tests without pinning the loop variables, causing all subtests on Go < 1.22 to test only the final iteration's inputs, making the entire table-driven suite effectively a no-op for correctness coverage.
  • These bugs have been flagged across 25+ unresolved prior review comments on multiple files (form_test.go, query_test.go, innerflag_test.go, requestflag_test.go), none of which have been addressed, suggesting a systemic pattern rather than isolated oversights.
Files requiring special attention
  • internal/requestflag/requestflag_test.go
  • pkg/cmd/flagoptions_test.go
  • internal/apiquery/query_test.go
  • internal/apiform/form_test.go
  • internal/requestflag/innerflag_test.go

@stainless-app stainless-app Bot force-pushed the release-please--branches--main--changes--next branch from 97312ab to e1ca22b Compare April 18, 2026 00:30
@entelligence-ai-pr-reviews
Copy link
Copy Markdown

entelligence-ai-pr-reviews Bot commented Apr 18, 2026

EntelligenceAI PR Summary

This PR delivers the v0.2.0 release of the Hyperspell CLI SDK with new features, refactors, and quality improvements.

  • Introduces --raw-output/-r CLI flag for stripping JSON string quotes (jq -r style)
  • Adds stdin support (-) for binary file parameters via new onceStdinReader with /dev/stdin//dev/fd/0 aliases
  • Implements parameter aliasing via DataAliases in Flag/InnerFlag structs with applyDataAliases/rewriteAliases translation
  • Adds fileUpload struct propagating filename and MIME content-type for multipart file inputs
  • Adds upfront HYPERSPELL_BASE_URL environment variable validation and ValidateBaseURL for --base-url flag
  • Refactors ShowJSON/ShowJSONIterator across all command handlers to use ShowJSONOpts struct with ExplicitFormat, RawOutput, Transform, Stdout, and Stderr fields
  • Adds workflow_dispatch trigger to publish-release workflow for manual execution
  • Enables parallel test execution across apiform, apiquery, autocomplete, jsonview, requestflag, and cmdutil test suites
  • Bumps @stdy/cli from 0.20.2 to 0.22.1 in mock/test scripts
  • Fixes bootstrap script unbound variable, link script module replace guard, and README examples

Confidence Score: 3/5 - Review Recommended

Review recommended — this PR delivers meaningful new features (raw output flag, stdin support, parameter aliasing, file upload propagation) but carries a significant number of unresolved correctness concerns from previous reviews that have not been addressed. Specifically, t.Parallel() is used inside for range loops in internal/apiform/form_test.go, internal/apiquery/query_test.go, and internal/requestflag/innerflag_test.go without capturing loop variables (test, name, tt) as local copies, which on Go < 1.22 causes all parallel subtests to execute with the final loop iteration's values, making the tests silently incorrect. Additionally, internal/requestflag/requestflag_test.go has parallel subtests sharing mutable flag instances (strFlag, superstitiousIntFlag, boolFlag) from the outer TestFlagSet scope, introducing data races. These are pre-existing unresolved concerns raised in prior reviews, not newly introduced by this PR's diff, but their persistence without resolution is a blocker for confident merge.

Key Findings:

  • In internal/apiform/form_test.go, internal/apiquery/query_test.go, and internal/requestflag/innerflag_test.go, t.Parallel() is called inside for name, test := range tests / for _, tt := range tests loops without shadowing the loop variables — on Go < 1.22 this causes every parallel subtest closure to capture the same shared variable, leading all subtests to run with the last iteration's values and producing false-positive test passes.
  • In internal/requestflag/requestflag_test.go, parallel subtests share outer-scope mutable flag instances (strFlag, superstitiousIntFlag, boolFlag) without synchronization, which introduces a data race and can cause non-deterministic test failures under -race.
  • The new features themselves (stdin via onceStdinReader, --raw-output flag, DataAliases / applyDataAliases, fileUpload struct) appear well-scoped and the implementation strategy is sound, but test reliability issues undermine confidence in the correctness guarantees the test suite is supposed to provide.
  • 42 unresolved comments from previous reviews remain open with no evidence of resolution or explicit acknowledgment, which is an unusually high backlog and suggests the review process has not converged before the release cut.
Files requiring special attention
  • internal/apiform/form_test.go
  • internal/apiquery/query_test.go
  • internal/requestflag/innerflag_test.go
  • internal/requestflag/requestflag_test.go

@entelligence-ai-pr-reviews
Copy link
Copy Markdown

This PR delivers the v0.2.0 release of the Hyperspell CLI, introducing several new capabilities and a broad refactor of the output and flag systems.

  • Adds --raw-output/-r flag to strip JSON quotes from string output (mimicking jq -r)
  • Adds stdin support via - for binary file parameters with MIME content-type forwarding
  • Introduces parameter aliasing (x-stainless-cli-data-alias) to map user-facing alias keys to canonical API field names in piped YAML/JSON and flag maps
  • Refactors ShowJSON/ShowJSONIterator across all 12+ command handlers to accept a ShowJSONOpts struct, enabling ExplicitFormat, RawOutput, and stdout/stderr injection for testability
  • Adds early HYPERSPELL_BASE_URL environment variable validation at startup and ValidateBaseURL parse-time flag validation
  • Adds TTY fallback behavior for the explore format with optional warning when explicitly requested
  • Extends InnerFlag and Flag structs with DataAliases field and accessor methods; updates HasOuterFlag and InRequest interfaces accordingly
  • Enables parallel test execution (t.Parallel()) across all major test suites
  • Migrates tests from manual os.Chdir patterns to t.Chdir(t.TempDir()) and from assert to require for fail-fast behavior
  • Bumps version to 0.2.0 across manifest, version constant, and changelog
  • Updates OpenAPI spec URL/hash and adds workflow_dispatch trigger to release workflow

@stainless-app stainless-app Bot force-pushed the release-please--branches--main--changes--next branch from e1ca22b to d3872d3 Compare April 18, 2026 08:14
@stainless-app stainless-app Bot force-pushed the release-please--branches--main--changes--next branch from d3872d3 to 6a55d31 Compare April 18, 2026 08:16
@entelligence-ai-pr-reviews
Copy link
Copy Markdown

This PR delivers the v0.2.0 release of the Hyperspell CLI with new features, refactors, and bug fixes.

  • Adds --raw-output / -r flag for jq-style raw string JSON output (pkg/cmd/cmd.go, pkg/cmd/cmdutil.go)
  • Introduces stdin support via - for binary file parameters with mutual exclusion against piped YAML/JSON input (pkg/cmd/flagoptions.go)
  • Adds CLI data aliasing via DataAliases field, enabling x-stainless-cli-data-alias key rewriting in request bodies (internal/requestflag/, pkg/cmd/flagoptions.go)
  • Forwards filename and content-type metadata from file inputs using a new fileUpload struct (pkg/cmd/flagoptions.go)
  • Refactors ShowJSON/ShowJSONIterator across all command handlers to use a unified ShowJSONOpts struct (pkg/cmd/cmdutil.go and 12 handler files)
  • Adds upfront HYPERSPELL_BASE_URL environment variable validation and ValidateBaseURL flag validator (cmd/hyperspell/main.go, pkg/cmd/cmd.go, pkg/cmd/cmdutil.go)
  • Adds TTY fallback to json format with a warning when explore is requested in non-TTY context (pkg/cmd/cmdutil.go)
  • Parallelizes test execution across 7 test files with t.Parallel() additions
  • Bumps version to 0.2.0 in manifest, version constant, and changelog
  • Adds workflow_dispatch trigger to the release GitHub Actions workflow
  • Validates replacement target in scripts/link before running go mod edit

@entelligence-ai-pr-reviews
Copy link
Copy Markdown

This PR delivers the v0.2.0 release of the Hyperspell CLI with significant feature additions, a broad refactoring of the JSON output layer, and test suite improvements.

  • Adds --raw-output/-r CLI flag to print string values without JSON quotes (pkg/cmd/cmd.go, pkg/cmd/cmdutil.go)
  • Introduces ShowJSONOpts struct replacing positional arguments in ShowJSON/ShowJSONIterator across all 12+ command handler files
  • Adds ValidateBaseURL for improved base URL scheme validation at both parse time and startup
  • Implements stdin support for @-prefixed binary file parameters via onceStdinReader in pkg/cmd/flagoptions.go
  • Adds fileUpload struct to propagate filename and content-type metadata for multipart file uploads
  • Introduces parameter aliasing (DataAliases) in InnerFlag/Flag structs and applyDataAliases/rewriteAliases functions for YAML/JSON piped input
  • Adds graceful fallback from explore to json format when output is not a TTY
  • Enables parallel test execution via t.Parallel() across all test files
  • Bumps @stdy/cli from 0.20.2 to 0.22.1 in mock/test scripts
  • Fixes scripts/link to skip module replacement when target path/module is unresolvable
  • Updates OpenAPI spec hash in .stats.yml to reflect upstream API changes

@stainless-app stainless-app Bot force-pushed the release-please--branches--main--changes--next branch from 6a55d31 to 5e2274b Compare April 22, 2026 18:31
@stainless-app stainless-app Bot force-pushed the release-please--branches--main--changes--next branch from 5e2274b to 9fcce21 Compare April 22, 2026 19:23
@stainless-app stainless-app Bot force-pushed the release-please--branches--main--changes--next branch from 9fcce21 to 02a071b Compare April 22, 2026 19:27
@stainless-app stainless-app Bot force-pushed the release-please--branches--main--changes--next branch from 02a071b to ace8646 Compare April 22, 2026 19:39
@stainless-app stainless-app Bot force-pushed the release-please--branches--main--changes--next branch from ace8646 to 7f35321 Compare April 22, 2026 19:52
@stainless-app stainless-app Bot force-pushed the release-please--branches--main--changes--next branch from 7f35321 to 6731d3f Compare April 22, 2026 23:13
@stainless-app stainless-app Bot force-pushed the release-please--branches--main--changes--next branch from 6731d3f to 37fae15 Compare April 23, 2026 04:06
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

0 participants