resolving a member's task symlink needs their identity too
One layer below yesterday's fix, and it looked identical on screen: the job was
found, then declared to have written nothing.
`loadBackgroundTask` resolved the located path with `realpathSync`, as the
platform. Resolving a link needs `x` on every directory above it, and
`/tmp/claude-<uid>` is `drwx------` — so it threw EACCES on an INTACT link, and
the catch below it reported that as a dangling symlink and returned null. The
tray polls, gets `{kind:'pending'}`, and shows "Nothing written yet" forever.
The lookup fix could not have exposed this: it made the file findable, which is
precisely what let execution reach the line that then threw it away.
`realpath -e` rather than `readlink -f`, because `-e` requires every component to
exist — that keeps a genuinely dangling link reporting as one instead of
resolving to a path that is not there. Verified against symlink, plain file,
dangling link and missing path: `realpath -e` and `realpathSync` agree on all
four, so the owner path is unchanged.
Audited the rest of claude-sessions.ts for the same shape. Every remaining
mention of `statSync`/`readdirSync`/`Bun.Glob` in that file is a comment
explaining why it is NOT used.
Live coverage extended: the member resolves their own link, the platform gets
null. Skips without OFFICER_TEST_MEMBER.
tsgo clean, frontend builds, 865 pass / 7 fail unchanged, 7 skips.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
This commit is contained in:
@@ -1,9 +1,9 @@
|
||||
import { realpathSync } from 'node:fs';
|
||||
import { dirname, join } from 'node:path';
|
||||
import { DATA_PATH } from '../../data-path';
|
||||
import {
|
||||
appendTextAs,
|
||||
findPathAs,
|
||||
realpathAs,
|
||||
listTranscriptsAs,
|
||||
readHeadAs,
|
||||
readTailAs,
|
||||
@@ -800,12 +800,12 @@ export function loadBackgroundTask(who: ChatIdentity, taskId: string): Backgroun
|
||||
const found = findTaskOutput(who, taskId);
|
||||
if (!found) return null;
|
||||
|
||||
let target = found;
|
||||
try {
|
||||
target = realpathSync(found);
|
||||
} catch {
|
||||
return null; // a dangling symlink — the task registered before its transcript existed
|
||||
}
|
||||
// As the member, for the same reason the lookup is: resolving a link needs `x` on every directory above
|
||||
// it, and `/tmp/claude-<uid>` is `drwx------`. Resolving it as the platform threw EACCES on an INTACT
|
||||
// link, and the catch reported that as dangling — so a member's job was found and then declared to have
|
||||
// written nothing, which is exactly what it looked like on screen.
|
||||
const target = realpathAs(who.osUser, found);
|
||||
if (!target) return null; // dangling, or gone between the lookup and here
|
||||
|
||||
if (target.endsWith('.jsonl')) {
|
||||
const detail = parseClaudeTranscript(who.osUser, target, taskId);
|
||||
|
||||
Reference in New Issue
Block a user