Skip to content

Five .env parsers disagree: two return an empty env on CRLF files, three mis-key an export prefix #2100

Description

@bowlax

Version

LifeOS 7.40.4 (verified against 5e2f2e8)

What is broken

The install carries five independent .env parsers, and they disagree on three inputs. Two of those disagreements are defects. PULSE/checks/calendar.ts and TOOLS/YouTubeApi.ts parse each line with ^([^#=]+)=(.*)$, and JavaScript treats a carriage return as a line terminator, so . will not match one and $ will not match before one. Given a .env saved with Windows line endings, neither file returns a truncated value: both return an empty object, and every caller then reports its credential as absent. TOOLS/healthsync/store.ts splits on /\r?\n/ and is unaffected, so the same credential file works for the health-sync subsystem and fails for these two. Separately, a .env written with export FOO=bar, which is what anyone sourcing the file in a shell will have, yields a key named literally export FOO in PULSE/pulse.ts, PULSE/checks/calendar.ts and TOOLS/YouTubeApi.ts; FOO is never set. TOOLS/healthsync/store.ts strips the prefix and is again the only one that behaves.

Where (file:line)

LIFEOS/PULSE/checks/calendar.ts:22 and LIFEOS/TOOLS/YouTubeApi.ts:65 (carriage return); LIFEOS/PULSE/pulse.ts:30, LIFEOS/PULSE/checks/calendar.ts:22, LIFEOS/TOOLS/YouTubeApi.ts:65 and LIFEOS/TOOLS/PangramScore.ts:70 (export prefix). Correct behaviour for comparison: LIFEOS/TOOLS/healthsync/store.ts:149.

Repro on a clean tree

# Fake HOME so nothing touches a real install.
mkdir -p /tmp/lifeos-crlf/.claude

# Same two keys, Windows line endings.
printf 'YOUTUBE_API_KEY=abc123\r\nYOUTUBE_CHANNEL_ID=UC_test\r\n' > /tmp/lifeos-crlf/.claude/.env
HOME=/tmp/lifeos-crlf bun LIFEOS/TOOLS/YouTubeApi.ts
# Error: YOUTUBE_API_KEY not set

# Identical keys, Unix line endings.
printf 'YOUTUBE_API_KEY=abc123\nYOUTUBE_CHANNEL_ID=UC_test\n' > /tmp/lifeos-crlf/.claude/.env
HOME=/tmp/lifeos-crlf bun LIFEOS/TOOLS/YouTubeApi.ts
# prints usage — the key was accepted

# The export prefix, Unix line endings.
printf 'export YOUTUBE_API_KEY=abc123\n' > /tmp/lifeos-crlf/.claude/.env
HOME=/tmp/lifeos-crlf bun LIFEOS/TOOLS/YouTubeApi.ts
# Error: YOUTUBE_API_KEY not set

# Second file, same cause.
printf 'GOOGLE_CALENDAR_REFRESH_TOKEN=rt\r\nGMAIL_CLIENT_ID=cid\r\nGMAIL_CLIENT_SECRET=cs\r\n' > /tmp/lifeos-crlf/.claude/.env
HOME=/tmp/lifeos-crlf bun LIFEOS/PULSE/checks/calendar.ts
# GOOGLE_CALENDAR_REFRESH_TOKEN not set

printf 'GOOGLE_CALENDAR_REFRESH_TOKEN=rt\nGMAIL_CLIENT_ID=cid\nGMAIL_CLIENT_SECRET=cs\n' > /tmp/lifeos-crlf/.claude/.env
HOME=/tmp/lifeos-crlf bun LIFEOS/PULSE/checks/calendar.ts
# Calendar check failed: Token refresh failed — the keys parsed, the fake values were rejected by Google

Negative control

On unpatched 7.40.4, with YOUTUBE_API_KEY=abc123 present in ~/.claude/.env and the file saved with CRLF endings, TOOLS/YouTubeApi.ts prints Error: YOUTUBE_API_KEY not set and exits. The same file with LF endings prints the usage banner. PULSE/checks/calendar.ts reports GOOGLE_CALENDAR_REFRESH_TOKEN not set on the CRLF file and proceeds to a token refresh on the LF file. With export prefixes and LF endings, TOOLS/YouTubeApi.ts reports the key unset while the file plainly contains it.

Behaviour of each parser against the cases that separate them, each run verbatim:

Input pulse.ts calendar.ts / YouTubeApi.ts healthsync/store.ts
A=1\r\n {"A":"1"} {} {"A":"1"}
export A=1\n {"export A":"1"} {"export A":"1"} {"A":"1"}
1BAD=x\nA=1\n {"1BAD":"x","A":"1"} {"1BAD":"x","A":"1"} {"A":"1"}

Suggested fix

The parser in TOOLS/healthsync/store.ts already handles all three rows. Promoting it to a shared module and having the other four call it removes both defects and stops the five drifting further apart. Untested as a refactor of this tree, though the same consolidation is running in a fork with the behaviour table above as its test cases, and I am happy to open a PR if that would help.

One caveat on scope: PULSE/pulse.ts loads .env before the billing guard that strips ANTHROPIC_API_KEY and ANTHROPIC_AUTH_TOKEN, so any replacement there has to keep that ordering.

Activity

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions