Skip to content

Parse and render stack frames in rwx lint output#369

Merged
robinaugh merged 1 commit intomainfrom
feat/lint-stack-frames
Feb 23, 2026
Merged

Parse and render stack frames in rwx lint output#369
robinaugh merged 1 commit intomainfrom
feat/lint-stack-frames

Conversation

@robinaugh
Copy link
Contributor

@robinaugh robinaugh commented Feb 19, 2026

Goes with rwx-cloud/language-server#30 and #370 (already merged)

Summary

  • Adds StackTrace []messages.StackEntry field to CheckDiagnostic
  • Parses relatedInformation from LSP diagnostic responses into stack trace entries (strips file:// prefix, converts 0-based to 1-based line/column)
  • Renders stack frames in multiline output using the existing at name (file:line:col) format
  • StackTrace appears in JSON output via Go's default PascalCase marshaling

Context

Depends on rwx-cloud/language-server#30, which populates relatedInformation on LSP diagnostics from the parser's stack trace arrays. Without that change, the language server never emits relatedInformation, so this CLI code has nothing to parse.

Before / After

rwx lint <file>

Before

╰─⠠⠵ rwx lint /private/tmp/test-lint/.rwx/ci.yml
/private/tmp/test-lint/.rwx/ci.yml:2:3  [error]
A base layer must have a `tag` key if it has an `os` key

/private/tmp/test-lint/.rwx/ci.yml:4:1  [error]
Unexpected property `shared`
Expected one of the following keys: `aliases`, `base`, `concurrency-pools`, `on`, `tasks`, `tool-cache`

/private/tmp/test-lint/.rwx/ci.yml:9:9  [error]
Unexpected property `badproperty`
Expected one of the following keys: `after`, `agent`, `auto-cancel`, `background-processes`, `cache`, `docker`, `env`, `env-config`, `filter`, `health-timeout`, `if`, `key`, `outputs`, `parallel`, `retry`, `run`, `terminate-grace-period-seconds`, `timeout`, `timeout-minutes`, `tool-cache`, `use`

Checked 1 file and found 3 problems.

After

╰─⠠⠵ ./rwx lint /private/tmp/test-lint/.rwx/ci.yml

/private/tmp/test-lint/.rwx/ci.yml:2:3  [error]
A base layer must have a `tag` key if it has an `os` key

/private/tmp/test-lint/.rwx/ci.yml:4:1  [error]
Unexpected property `shared`
Expected one of the following keys: `aliases`, `base`, `concurrency-pools`, `on`, `tasks`, `tool-cache`

/private/tmp/test-lint/.rwx/ci.yml:9:9  [error]
Unexpected property `badproperty`
Expected one of the following keys: `after`, `agent`, `auto-cancel`, `background-processes`, `cache`, `docker`, `env`, `env-config`, `filter`, `health-timeout`, `if`, `key`, `outputs`, `parallel`, `retry`, `run`, `terminate-grace-period-seconds`, `timeout`, `timeout-minutes`, `tool-cache`, `use`
  at /private/tmp/test-lint/.rwx/ci.yml:5:3

Checked 1 file and found 3 problems.

rwx lint <file> -o json

Before

╰─⠠⠵ rwx lint /private/tmp/test-lint/.rwx/ci.yml -o json 
{"Diagnostics":[{"Severity":"error","Message":"A base layer must have a `tag` key if it has an `os` key","FilePath":"/private/tmp/test-lint/.rwx/ci.yml","Line":2,"Column":3},{"Severity":"error","Message":"Unexpected property `shared`\nExpected one of the following keys: `aliases`, `base`, `concurrency-pools`, `on`, `tasks`, `tool-cache`","FilePath":"/private/tmp/test-lint/.rwx/ci.yml","Line":4,"Column":1},{"Severity":"error","Message":"Unexpected property `badproperty`\nExpected one of the following keys: `after`, `agent`, `auto-cancel`, `background-processes`, `cache`, `docker`, `env`, `env-config`, `filter`, `health-timeout`, `if`, `key`, `outputs`, `parallel`, `retry`, `run`, `terminate-grace-period-seconds`, `timeout`, `timeout-minutes`, `tool-cache`, `use`","FilePath":"/private/tmp/test-lint/.rwx/ci.yml","Line":9,"Column":9}],"FileCount":1,"FixedCount":0}

After

╰─⠠⠵ ./rwx lint /private/tmp/test-lint/.rwx/ci.yml -o json
{"Diagnostics":[{"Severity":"error","Message":"A base layer must have a `tag` key if it has an `os` key","FilePath":"/private/tmp/test-lint/.rwx/ci.yml","Line":2,"Column":3,"StackTrace":null},{"Severity":"error","Message":"Unexpected property `shared`\nExpected one of the following keys: `aliases`, `base`, `concurrency-pools`, `on`, `tasks`, `tool-cache`","FilePath":"/private/tmp/test-lint/.rwx/ci.yml","Line":4,"Column":1,"StackTrace":null},{"Severity":"error","Message":"Unexpected property `badproperty`\nExpected one of the following keys: `after`, `agent`, `auto-cancel`, `background-processes`, `cache`, `docker`, `env`, `env-config`, `filter`, `health-timeout`, `if`, `key`, `outputs`, `parallel`, `retry`, `run`, `terminate-grace-period-seconds`, `timeout`, `timeout-minutes`, `tool-cache`, `use`","FilePath":"/private/tmp/test-lint/.rwx/ci.yml","Line":9,"Column":9,"StackTrace":[{"file_name":"/private/tmp/test-lint/.rwx/ci.yml","line":5,"column":3,"name":""}]}],"FileCount":1,"FixedCount":0}

Test plan

  • go test ./internal/... ./cmd/... passes
  • golangci-lint run ./... passes
  • Create a YAML file with an alias that merges invalid content, run rwx lint and verify stack frames appear in multiline output
  • Run rwx lint -o json and verify StackTrace appears on diagnostics
  • Run rwx lint -o oneline and verify no stack frames (by design)

@robinaugh robinaugh self-assigned this Feb 20, 2026
Parse relatedInformation from LSP diagnostic responses into StackTrace
entries on CheckDiagnostic. Render stack frames in multiline output
using the same "at name (file:line:col)" format as API error messages.
The StackTrace field also appears in JSON output via default marshaling.
@robinaugh robinaugh force-pushed the feat/lint-stack-frames branch from f70e0c1 to 570509c Compare February 20, 2026 14:23
@robinaugh robinaugh marked this pull request as ready for review February 20, 2026 14:23
@robinaugh robinaugh merged commit 33bc426 into main Feb 23, 2026
1 check passed
@robinaugh robinaugh deleted the feat/lint-stack-frames branch February 23, 2026 14:21
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.

2 participants