Problem
cants exits 0 when it fails. Two cases, both measured on 1.3.0:
$ cants -i /nonexistent/xyz -o out ; echo "rc=$?"
rc=0
$ cat out/analysis.json # written anyway
{"schema_version":"2.0.0","language":"typescript","max_level":1,
"analyzer":{"name":"codeanalyzer-typescript","version":"1.3.0"},
"application":{"id":"can://typescript/xyz","kind":"application","symbol_table":{}, ...}}
$ cants -i vscode -o out ; echo "rc=$?"
[codeanalyzer-ts] FATAL TypeError: Type error
at structuredClone (unknown)
at finalizeAnalysis (...)
rc=0
So the analyzer returns success after printing FATAL, and returns success for an input path that does not exist — emitting a schema-valid payload describing an empty application, whose id is derived from the last path segment of a directory that was never read.
Why it matters
Every consumer runs this as a subprocess and the exit code is the only cheap health signal. A wrapper written the obvious way — subprocess.run(..., check=True) — treats both cases as a successful run. The nonexistent-path case is worse than the crash, because it hands back a well-formed payload: an agent asking "what does this project contain?" is told, in schema-conformant JSON, that the answer is nothing.
The FATAL case is at least distinguishable by the absent output directory, and the empty-input case by symbol_table == {} — but both require the consumer to know to look, and neither is what an exit code is for.
Expected
- A nonexistent or unreadable
-i path is an error: non-zero exit, no analysis.json written.
- Any path that prints
FATAL exits non-zero.
An empty symbol_table should mean "this project has no analysable sources", which is a real and different answer from "the input did not exist".
Environment
codeanalyzer-typescript 1.3.0 (PyPI wheel, bundled Bun binary), macOS 15 arm64.
Related: the crash in the second case is #180. This issue is about the exit code and the payload, which are independent of what went wrong.
Problem
cantsexits 0 when it fails. Two cases, both measured on 1.3.0:So the analyzer returns success after printing
FATAL, and returns success for an input path that does not exist — emitting a schema-valid payload describing an empty application, whoseidis derived from the last path segment of a directory that was never read.Why it matters
Every consumer runs this as a subprocess and the exit code is the only cheap health signal. A wrapper written the obvious way —
subprocess.run(..., check=True)— treats both cases as a successful run. The nonexistent-path case is worse than the crash, because it hands back a well-formed payload: an agent asking "what does this project contain?" is told, in schema-conformant JSON, that the answer is nothing.The
FATALcase is at least distinguishable by the absent output directory, and the empty-input case bysymbol_table == {}— but both require the consumer to know to look, and neither is what an exit code is for.Expected
-ipath is an error: non-zero exit, noanalysis.jsonwritten.FATALexits non-zero.An empty
symbol_tableshould mean "this project has no analysable sources", which is a real and different answer from "the input did not exist".Environment
codeanalyzer-typescript1.3.0 (PyPI wheel, bundled Bun binary), macOS 15 arm64.Related: the crash in the second case is #180. This issue is about the exit code and the payload, which are independent of what went wrong.