From bc4404203c379c4d278e8be687f40e690b69603b Mon Sep 17 00:00:00 2001 From: can1357 Date: Wed, 12 Aug 2026 01:16:11 +0200 Subject: [PATCH] feat(coding-agent/cleanse): updated ty parser regex and test cases - Update the ty parser regex to correctly match file path and position before the severity and error code. - Adjust discovery prompt documentation and test cases to match the revised ty output format. --- packages/coding-agent/src/cleanse/parsers.ts | 12 +-- .../src/cleanse/prompts/discovery.md | 88 +++++++++---------- packages/coding-agent/test/cleanse.test.ts | 20 ++++- 3 files changed, 67 insertions(+), 53 deletions(-) diff --git a/packages/coding-agent/src/cleanse/parsers.ts b/packages/coding-agent/src/cleanse/parsers.ts index 7d9172bc4..3947a3dcc 100644 --- a/packages/coding-agent/src/cleanse/parsers.ts +++ b/packages/coding-agent/src/cleanse/parsers.ts @@ -488,14 +488,14 @@ function parseTy(input: CleanseParserInput): CleanseDiagnostic[] { const diagnostics: CleanseDiagnostic[] = []; const text = sanitizeText(`${input.stdout}\n${input.stderr}`); for (const line of text.split("\n")) { - const match = /^(error|warning|info)\[([^\]]+)\]\s+(.+?):(\d+):(\d+):\s+(.*)$/.exec(line.trim()); + const match = /^(.+?):(\d+):(\d+):\s+(error|warning|info)\[([^\]]+)\]\s+(.*)$/.exec(line.trim()); if (!match) continue; addDiagnostic(diagnostics, input, { - file: match[3], - line: Number.parseInt(match[4], 10), - column: Number.parseInt(match[5], 10), - code: match[2], - severity: match[1], + file: match[1], + line: Number.parseInt(match[2], 10), + column: Number.parseInt(match[3], 10), + code: match[5], + severity: match[4], message: match[6], }); } diff --git a/packages/coding-agent/src/cleanse/prompts/discovery.md b/packages/coding-agent/src/cleanse/prompts/discovery.md index 46c7ebc28..b3d8f28ad 100644 --- a/packages/coding-agent/src/cleanse/prompts/discovery.md +++ b/packages/coding-agent/src/cleanse/prompts/discovery.md @@ -1,56 +1,56 @@ -- You NEVER edit project files; this is a read-and-verify discovery task. -- You MUST verify every command you propose by running it once. -- Your final message MUST be exactly one JSON object matching the schema below — no prose, no code fences. +- NEVER edit project files — read-and-verify discovery only. +- MUST run each proposed command once. +- Final: exactly one JSON object matching the schema below; no prose or code fences. # Checker Discovery -The user asked `omp cleanse` to detect and repair: **{{request}}** +User requested `omp cleanse` detect and repair: **{{request}}** -Determine which project command(s) surface exactly those diagnostics so the orchestrator can run them, parse their output, and dispatch repair agents. +Identify project command(s) surfacing exactly these diagnostics for orchestrator execution, output parsing, and repair-agent dispatch. -1. Inspect the project (manifests, configs, lockfiles, scripts) to identify the relevant tooling. -2. Determine the exact command and working directory. Prefer project-local binaries (`node_modules/.bin`, `.venv/bin`, wrappers like `gradlew`) over global tools. -3. Prefer a machine-readable output flag matching a known parser below. Otherwise pick a format that prints gcc-style `file:line:col: severity: message` lines and use parser `generic`. -4. Run the command once to verify it executes and its output matches the chosen parser. A non-zero exit with parseable diagnostics is fine; a crash or usage error is not. -5. If several commands are needed to cover the request, return one entry per command. +1. Inspect manifests, configs, lockfiles, and scripts for relevant tooling. +2. Determine exact command and working directory. Prefer project-local binaries (`node_modules/.bin`, `.venv/bin`, wrappers like `gradlew`) over global tools. +3. Prefer machine-readable output matching a known parser below. Otherwise use gcc-style `file:line:col: severity: message` output and parser `generic`. +4. Run once: verify execution and output matches the chosen parser. Non-zero exit with parseable diagnostics: fine; crash or usage error: not. +5. If multiple commands cover the request, return one entry per command. ## Known parsers -| id | expected output | +|id|expected output| |---|---| -| `rust` | `cargo … --message-format=json` | -| `rust-test` | `cargo test … --message-format=json` | -| `go` | `go vet -json` | -| `go-test` | `go test -json` | -| `staticcheck` | `staticcheck -f json` | -| `golangci` | golangci-lint default text output | -| `ruff` | `ruff check --output-format=json` | -| `pyright` | `pyright`/`basedpyright` `--outputjson` | -| `mypy` | mypy default text output | -| `pylint` | `pylint --output-format=json` | -| `flake8` | flake8 default text output | -| `ty` | `ty check --output-format concise` | -| `eslint` | `eslint --format=json` | -| `biome` | `biome check --reporter=json` | -| `oxlint` | unix-format lines `file:line:col: message [Error/rule]` (`--format=unix`) | -| `deno-lint` | `deno lint --json` | -| `stylelint` | `stylelint --formatter json` | -| `rubocop` | `rubocop --format json` | -| `phpstan` | `phpstan analyse --error-format=json` | -| `psalm` | `psalm --output-format=json` | -| `swiftlint` | `swiftlint lint --reporter json` | -| `dart` | `dart analyze --format machine` | -| `credo` | `mix credo --format=json` | -| `shellcheck` | `shellcheck --format=json1` | -| `hlint` | `hlint --json` | -| `terraform` | `terraform validate -json` | -| `tflint` | `tflint --format=json` | -| `actionlint` | actionlint with its JSON `-format` template | -| `generic` | gcc-style `file:line:col: severity: message` lines (tsc/tsgo `--pretty false`, mypy, clang, zig, MSVC-style) | +|`rust`|`cargo … --message-format=json`| +|`rust-test`|`cargo test … --message-format=json`| +|`go`|`go vet -json`| +|`go-test`|`go test -json`| +|`staticcheck`|`staticcheck -f json`| +|`golangci`|golangci-lint default text output| +|`ruff`|`ruff check --output-format=json`| +|`pyright`|`pyright`/`basedpyright` `--outputjson`| +|`mypy`|mypy default text output| +|`pylint`|`pylint --output-format=json`| +|`flake8`|flake8 default text output| +|`ty`|`ty check --output-format concise`| +|`eslint`|`eslint --format=json`| +|`biome`|`biome check --reporter=json`| +|`oxlint`|unix-format lines `file:line:col: message [Error/rule]` (`--format=unix`)| +|`deno-lint`|`deno lint --json`| +|`stylelint`|`stylelint --formatter json`| +|`rubocop`|`rubocop --format json`| +|`phpstan`|`phpstan analyse --error-format=json`| +|`psalm`|`psalm --output-format=json`| +|`swiftlint`|`swiftlint lint --reporter json`| +|`dart`|`dart analyze --format machine`| +|`credo`|`mix credo --format=json`| +|`shellcheck`|`shellcheck --format=json1`| +|`hlint`|`hlint --json`| +|`terraform`|`terraform validate -json`| +|`tflint`|`tflint --format=json`| +|`actionlint`|actionlint with its JSON `-format` template| +|`generic`|gcc-style `file:line:col: severity: message` lines (tsc/tsgo `--pretty false`, mypy, clang, zig, MSVC-style)| ## Output schema @@ -68,7 +68,7 @@ Determine which project command(s) surface exactly those diagnostics so the orch } ``` -- `command`: argv array; the first element is a binary name or project-relative path. Never wrap in a shell. -- `cwd`: project-relative working directory; omit for the project root. -- `parser`: one of the known parser ids; omit for `generic`. -- Return `"checkers": []` only when nothing in this project can produce the requested diagnostics. +- `command`: argv array; first element: binary name or project-relative path. NEVER shell-wrap. +- `cwd`: project-relative working directory; omit for project root. +- `parser`: known parser id; omit for `generic`. +- Return `"checkers": []` only if nothing in this project produces the requested diagnostics. diff --git a/packages/coding-agent/test/cleanse.test.ts b/packages/coding-agent/test/cleanse.test.ts index c606e2942..49815ec08 100644 --- a/packages/coding-agent/test/cleanse.test.ts +++ b/packages/coding-agent/test/cleanse.test.ts @@ -362,9 +362,23 @@ describe("cleanse alternative-tooling parsers", () => { }); test("parses ty concise output", () => { - const diagnostics = parse("ty", "error[unresolved-import] src/main.py:1:8: Cannot resolve imported module\n"); - expect(diagnostics).toMatchObject([ - { file: "src/main.py", line: 1, column: 8, code: "unresolved-import", severity: "error" }, + const diagnostics = parse( + "ty", + "src/main.py:1:8: error[unresolved-import] Cannot resolve imported module `foo`\nFound 1 diagnostic\n", + ); + expect(diagnostics).toEqual([ + { + checker: "checker", + file: "src/main.py", + line: 1, + column: 8, + endLine: undefined, + endColumn: undefined, + code: "unresolved-import", + severity: "error", + message: "Cannot resolve imported module `foo`", + suggestion: undefined, + }, ]); });