Skip to content

fix: enforce absolute log paths, and name the real cause when one cannot be opened - #110

Closed
lukecotter wants to merge 5 commits into
mainfrom
fix/109-log-paths
Closed

fix: enforce absolute log paths, and name the real cause when one cannot be opened#110
lukecotter wants to merge 5 commits into
mainfrom
fix/109-log-paths

Conversation

@lukecotter

@lukecotter lukecotter commented Aug 11, 2026

Copy link
Copy Markdown
Collaborator

Two fixes from #109, and the naming rules the v2 rename (#107) will follow.

Refuse a relative logFilePath

All three analysis tools documented an absolute path and accepted any string. A relative one
resolved against the server's working directory — where the client spawned the server, not where
the caller is — so it read a different file or none, and reported neither.

The path is now declared once in apexLogSource.ts, the module the three tools already share for
loading a log, and refined to absolute. Refinements do not reach the JSON schema, so the tool
definitions are unchanged at ~1,053 tokens; pnpm run eval holds that.

execute_anonymous returns a filePath that callers feed straight back to those tools, so its
outputDir is resolved to absolute as well. A relative outputDir now anchors to the project root,
the base the default .apex-log-mcp already used, instead of the server's working directory.

Name the real cause when a log cannot be opened

Every failure to open the log reported Log file not found, so a permission error, a directory in
place of a file, or an exhausted descriptor table all sent the caller to look for a file that was
there. ENOENT still reports as missing; anything else names its code and keeps the original error
as cause.

Close cleanly on SIGTERM

Only SIGINT was trapped, so a supervised restart, a container stop, or a client that ends a stdio
server hit Node's default and exited without the clean close.

Warn when outputDir leaves the client roots

execute_anonymous created directories anywhere the process could write, from an agent-supplied
path. The MCP spec expects a server to work inside the roots the client declares, so this reports
rather than refuses: the log is still written, and both the response and stderr name where it went.
Silent for the default outputDir, for one inside a root, and for a client that declares no roots.
Symlinks are followed on both sides, so a link inside a root that points out of one still warns.

Naming rules

DEVELOPING.md gains a "Naming Tools and Fields" section: the apexlog_ prefix, a verb that states
the shape of the result, the banned verbs, and eight field rules. CLAUDE.md points at it and adds
"don't state what the caller can derive" to the shaping conventions. Docs only — nothing on the wire
changes. It is here because the rename commits that follow depend on it.

Testing

pnpm run build && pnpm run eval — 6 cases pass, definitions ~1,053 tokens.
pnpm exec jest — 259 pass. pnpm run lint clean. tsc --noEmit clean.

Refs #107
Closes #109

Record the rules the v2 rename follows: the apexlog_ prefix, a verb that
states the shape of the result, banned verbs, and eight field rules.
Add "don't state what the caller can derive" to the shaping conventions.

Refs #107
Every failure to open the log reported "Log file not found", so a
permission error, a directory in place of a file, or an exhausted
descriptor table all sent the caller to look for a file that was there.
Report ENOENT as missing, name the code otherwise, and keep the original
error as `cause`.

Refs #109
All three analysis tools documented an absolute path and accepted any
string. A relative one resolved against the server's working directory,
which is where the client spawned the server and not where the caller is,
so it read a different file or none and reported neither.

Declare the path once in apexLogSource, the module the three tools already
share for loading a log, and refine it to absolute. Refinements do not
reach the JSON schema, so the tool definitions are unchanged at ~1,053
tokens.

Resolve execute_anonymous's outputDir to absolute too, so the filePath it
returns stays one the analysis tools accept. A relative outputDir now
anchors to the project root, the base the default already used.

Refs #109
Only SIGINT was trapped, so a supervised restart, a container stop, or a
client that ends a stdio server hit Node's default and exited without the
clean close.

Refs #109
execute_anonymous created directories anywhere the process could write,
from an agent-supplied path. The MCP spec expects a server to work inside
the roots the client declares, so report rather than refuse: the log is
still written, and both the response and stderr name where it went.

Silent for the default outputDir, for one inside a root, and for a client
that declares no roots. Symlinks are followed on both sides.

Refs #109
@lcottercertinia
lcottercertinia added this pull request to the merge queue Aug 12, 2026
@github-merge-queue
github-merge-queue Bot removed this pull request from the merge queue due to no response for status checks Aug 12, 2026
@lukecotter

Copy link
Copy Markdown
Collaborator Author

Superseded. All five commits landed through the v2 series: the naming rules in #116, the absolute logFilePath refusal, the real open failure cause, the SIGTERM shutdown and the outputDir roots warning across #114-#117. This branch predates that series, so its remaining diff would revert it.

@lukecotter lukecotter closed this Aug 12, 2026
@lukecotter
lukecotter deleted the fix/109-log-paths branch August 12, 2026 16:08
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.

fix: read-error cause, relative paths, outputDir outside the client roots, SIGTERM

2 participants