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,
+ },
]);
});