docs: add nvm compatible wrapper - #15
Merged
Merged
Conversation
The suggested wrapper script wasn't playing nice with nvm because of all the relative paths. Use `npm root` to make sure we're always executing from where the global version is installed.
cnighswonger
added a commit
that referenced
this pull request
Apr 13, 2026
nvm-compatible wrapper with dynamic npm root -g path resolution (PR #15). Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
cnighswonger
added a commit
that referenced
this pull request
Apr 25, 2026
Same correction Codex caught on PR #80: PIPE_BUF atomicity applies to pipes/FIFOs only, not regular files. Previous draft overclaimed. Honest contract: POSIX guarantees O_APPEND offset+write atomicity (no torn offsets), NOT non-interleaved writes on regular files. Linux ext4/xfs/btrfs empirically don't interleave single write(2) of <4KB. Test #15 validates empirically. Escalation paths documented. Pushing the same correction across all three v3.2.0 directives so implementation doesn't inherit the wrong technical claim.
cnighswonger
added a commit
that referenced
this pull request
Apr 25, 2026
Same correction Codex caught on PR #80: PIPE_BUF atomicity applies to pipes/FIFOs only, not regular files. Previous draft overclaimed. Honest contract: POSIX guarantees O_APPEND offset+write atomicity (no torn offsets), NOT non-interleaved writes on regular files. Linux ext4/xfs/btrfs empirically don't interleave single write(2) of <4KB. Test #15 validates empirically. Escalation paths documented. Pushing the same correction across all three v3.2.0 directives so implementation doesn't inherit the wrong technical claim.
cnighswonger
added a commit
that referenced
this pull request
Apr 25, 2026
Rewrite proxy/extensions/usage-log.mjs to emit the exact MeterRowSchema
v:1 shape that claude-code-meter validates today. The proxy's
~/.claude/usage.jsonl becomes the canonical wire format both repos
agree on. claude-meter's strict z.strictObject validator stays
unchanged.
Field shape (29 fields, exact MeterRowSchema v:1):
- v: literal 1
- ts, sid (8-char hex, sticky for proxy lifetime)
- model, requested_model?, model_mismatch?
- speed (enum), service_tier
- input/output/cache_creation/cache_read/ephemeral_1h/ephemeral_5m/
web_search_requests
- q5h, q7d, q5h_reset, q7d_reset
- qstatus, qoverage, qclaim, qfallback_pct
- qoverage_util?, qrepresentative_claim?, org_id?, overage_disabled_reason?
- cache_hit_rate, q5h_delta, q7d_delta
Lifecycle:
- message_start: extract per-response state into ctx.meta._usageLog.start
(model, speed, service_tier, input/cache split, ephemeral split,
web_search_requests).
- message_delta: read from ctx.meta._usageLog, add output_tokens, parse
quota headers, assemble final record with sid + delta tracking,
append to JSONL.
Privacy:
- org_id is hashed with sha256(raw).digest("hex").slice(0, 16) — exact
same algorithm as claude-meter, never raw. Test 11/11b enforce this:
test 11 asserts bit-exact match; test 11b plants a secret raw org_id
and asserts it doesn't appear anywhere in the assembled record.
Activation: enabled:false default in extension export (existing
usage-log pattern). Users opt in by adding entry to proxy/extensions.json:
"usage-log": { "enabled": true, "order": 650 }
CACHE_FIX_USAGE_LOG=<path> overrides destination only — NOT an enable
flag.
Old 9-field shape (with peak_hour) is replaced wholesale. peak_hour is
NOT in MeterRowSchema and is dropped from the wire format
(recomputable from ts if needed). Old rows in users' existing
~/.claude/usage.jsonl will fail claude-meter's strict validator and
be skipped on the reader side — documented in CHANGELOG (separate
PR will add the CHANGELOG entry).
Atomicity: single-syscall fs.promises.appendFile of record + "\n".
POSIX O_APPEND offset+write atomicity (no torn offsets); non-
interleaved regular-file writes are empirical Linux behavior, not
POSIX. Test #15 (50 parallel writes) validates.
Cross-repo release ordering (per directive): cache-fix v3.2.0 ships
first; claude-meter v0.4.0 follows declaring >= cache-fix 3.2.0 as
required producer. Two PRs are NOT independently shippable.
21 tests, all green. Full suite 500/500.
cnighswonger
added a commit
that referenced
this pull request
Apr 25, 2026
* directive: claude-meter compat with proxy mode (#70) Cross-repo refactor: expand proxy/extensions/usage-log.mjs to a v:2 superset schema matching claude-meter's MeterRowSchema, then refactor claude-meter to consume from ~/.claude/usage.jsonl instead of via the NODE_OPTIONS preload that CC v2.1.113+ Bun binary ignores. Cache-fix side: schema expansion, sessionId, q5h/q7d delta tracking, documented schema-version 2. Default enabled:false for v3.2.0; default-on deferred to v3.3.0. Claude-meter side (separate PR in that repo): new jsonl-tailer ingest mode, deprecate preload export, update README. * review: add PR 81 claude-meter compat directive review * directive: address Codex review on claude-meter compat (#81) Substantial rewrite. Anchored the directive on a single coherent wire contract: proxy emits EXACTLY MeterRowSchema v:1 (the strict validator already in claude-meter). No new schema version, no proxy-only extras. Fixes for the six blockers: 1. Schema strictObject contradiction — abandoned the v:2 superset. Proxy now emits exact v:1 records. peak_hour dropped from output (recomputable from ts). claude-meter validator stays strict and unchanged. Single source of truth: MeterRowSchema in claude-meter. 2. Activation/config — corrected to match the actual usage-log pattern: enabled:false is the extension's own export default, opt-in is a JSON edit to extensions.json adding {"enabled": true, "order": 650}. CACHE_FIX_USAGE_LOG is path override only, never an enable flag. No extensions.json comments (it's JSON.parse'd). 3. org_id privacy — pinned to claude-meter's exact algorithm: sha256(raw).digest("hex").slice(0, 16). Specified in field-source table, in implementation choice, in tests, and in reviewer checklist. 4. State capture — explicit per-event responsibility documented. message_start populates ctx.meta._usageLog; message_delta reads from it and adds output_tokens. Test plan #4 and #5 cover this directly. 5. Migration/versioning — explicit cross-repo release ordering: proxy ships first, claude-meter v0.4.0 follows declaring >= cache-fix 3.2.0. Old 9-field rows fail strict validation and are skipped with a debug log on the reader side; documented in CHANGELOG. 6. Test path — corrected to test/proxy-usage-log.test.mjs (existing file). All file references updated. Plus: full per-field source table (29 fields, every MeterRowSchema field with its exact source), expanded reviewer checklist (16 items), expanded out-of-scope. * directive: correct JSONL atomicity claim on claude-meter compat (#81) Same correction Codex caught on PR #80: PIPE_BUF atomicity applies to pipes/FIFOs only, not regular files. Previous draft overclaimed. Honest contract: POSIX guarantees O_APPEND offset+write atomicity (no torn offsets), NOT non-interleaved writes on regular files. Linux ext4/xfs/btrfs empirically don't interleave single write(2) of <4KB. Test #15 validates empirically. Escalation paths documented. Pushing the same correction across all three v3.2.0 directives so implementation doesn't inherit the wrong technical claim. * feat: usage-log emits MeterRowSchema v:1 for claude-meter compat (#70) Rewrite proxy/extensions/usage-log.mjs to emit the exact MeterRowSchema v:1 shape that claude-code-meter validates today. The proxy's ~/.claude/usage.jsonl becomes the canonical wire format both repos agree on. claude-meter's strict z.strictObject validator stays unchanged. Field shape (29 fields, exact MeterRowSchema v:1): - v: literal 1 - ts, sid (8-char hex, sticky for proxy lifetime) - model, requested_model?, model_mismatch? - speed (enum), service_tier - input/output/cache_creation/cache_read/ephemeral_1h/ephemeral_5m/ web_search_requests - q5h, q7d, q5h_reset, q7d_reset - qstatus, qoverage, qclaim, qfallback_pct - qoverage_util?, qrepresentative_claim?, org_id?, overage_disabled_reason? - cache_hit_rate, q5h_delta, q7d_delta Lifecycle: - message_start: extract per-response state into ctx.meta._usageLog.start (model, speed, service_tier, input/cache split, ephemeral split, web_search_requests). - message_delta: read from ctx.meta._usageLog, add output_tokens, parse quota headers, assemble final record with sid + delta tracking, append to JSONL. Privacy: - org_id is hashed with sha256(raw).digest("hex").slice(0, 16) — exact same algorithm as claude-meter, never raw. Test 11/11b enforce this: test 11 asserts bit-exact match; test 11b plants a secret raw org_id and asserts it doesn't appear anywhere in the assembled record. Activation: enabled:false default in extension export (existing usage-log pattern). Users opt in by adding entry to proxy/extensions.json: "usage-log": { "enabled": true, "order": 650 } CACHE_FIX_USAGE_LOG=<path> overrides destination only — NOT an enable flag. Old 9-field shape (with peak_hour) is replaced wholesale. peak_hour is NOT in MeterRowSchema and is dropped from the wire format (recomputable from ts if needed). Old rows in users' existing ~/.claude/usage.jsonl will fail claude-meter's strict validator and be skipped on the reader side — documented in CHANGELOG (separate PR will add the CHANGELOG entry). Atomicity: single-syscall fs.promises.appendFile of record + "\n". POSIX O_APPEND offset+write atomicity (no torn offsets); non- interleaved regular-file writes are empirical Linux behavior, not POSIX. Test #15 (50 parallel writes) validates. Cross-repo release ordering (per directive): cache-fix v3.2.0 ships first; claude-meter v0.4.0 follows declaring >= cache-fix 3.2.0 as required producer. Two PRs are NOT independently shippable. 21 tests, all green. Full suite 500/500. * review: PR 81 claude-meter compat implementation review
3 tasks
vsits-proxy-builder Bot
pushed a commit
that referenced
this pull request
May 3, 2026
…ead review) The directive's auto-upgrade formula ttlValue === "5m" || detectedTier === "5m" ? "5m" : "1h" was tested for env=5m-wins (#14) and env=none-suppresses (#15) but not for explicit env=1h with detected=5m — the case the bug actually breaks. Lead flagged this in PR #100 review as the most important contract to lock in. Without it, a regression that silently fell back to ttlValue (ignoring detectedTier) would pass the rest of the suite. Issue-number transposition in lead's review was clarified separately (PR #100 directive ref #97 is correct; #98 was the image-strip issue already closed by PR #99). Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
cnighswonger
pushed a commit
that referenced
this pull request
May 3, 2026
* directive: TTL tier detection for proxy ttl-management (#97) Port preload.mjs's in-payload 5m-tier detection (lines 1815-1828) to the proxy ttl-management extension so users on CC v2.1.113+ stop losing this fix. Pure in-payload approach matches preload's proven mechanism; quota- header subscription is deferred to v2 if real-world telemetry shows v1 leaves a gap. Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com> * docs: codex review of PR #100 directive (TTL tier detection) * directive: revise TTL tier detection — split detection into pre-normalize extension Codex review of PR #100 flagged a blocking pipeline-order issue: cache-control-normalize (order 400) strips user-message cache_control markers before ttl-management (order 500) can read them, so the proposed in-payload detection would only see body.system markers. Revised approach: split detection into a new ttl-tier-detect extension at order 350 (before normalize), which sets ctx.meta._ttlTier. ttl- management consumes the flag at order 500 instead of scanning the body itself. Adds a pipeline-level integration test that exercises the real extension order to lock the rewire in. Refs Codex review at docs/code-reviews/pr-100-ttl-tier-detection-directive-review-2026-05-03.md. Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com> * docs: codex re-review of PR #100 directive (TTL tier detection) * directive: revise TTL tier detection — move detection to order 75 with full audit Codex re-review of PR #100 flagged a second pipeline-order miss: fresh- session-sort (order 250) destructures and discards cache_control on relocatable user blocks (lines 140, 164), which would lose a ttl=5m signal on, e.g., a relocated skills block before order 350 detection could see it. Revised: move ttl-tier-detect to order 75 (between read-only upstream-change-detection at 50 and output-efficiency-rewrite at 90), which is provably pre-mutation by every existing extension. Includes a full audit table of all 20 pipeline extensions classified by whether they touch cache_control. Pipeline tests reworded to assert observable output facts rather than 'ran first', and a fresh-session-sort relocatable-block regression test added (test #19). Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com> * docs: codex second re-review of PR #100 directive (TTL tier detection) * directive: third revision — fix audit orders and stale Acceptance reference Codex's second re-review of PR #100 flagged: - B: Acceptance section still referenced order 350 (stale from prior draft). - B: Audit table had wrong orders for content-strip and tool-input-normalize (had 350 and 280; actual extensions.json values are 330 and 340). - N: Test #19 wording overclaimed it could prove fresh-session-sort specifically did the strip; rephrased to assert observable end-state with the causal attribution moved to a static-reading citation. Audit table now reflects the live pipeline.mjs:23-25 logic (extensions.json overrides; .mjs defaults as fallback) and includes a Source/Default-enabled column for transparency on which extensions actually load by default. Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com> * docs: codex third re-review of PR #100 directive (TTL tier detection) * directive: add test #22 covering env=1h + detected=5m auto-upgrade (lead review) The directive's auto-upgrade formula ttlValue === "5m" || detectedTier === "5m" ? "5m" : "1h" was tested for env=5m-wins (#14) and env=none-suppresses (#15) but not for explicit env=1h with detected=5m — the case the bug actually breaks. Lead flagged this in PR #100 review as the most important contract to lock in. Without it, a regression that silently fell back to ttlValue (ignoring detectedTier) would pass the rest of the suite. Issue-number transposition in lead's review was clarified separately (PR #100 directive ref #97 is correct; #98 was the image-strip issue already closed by PR #99). Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com> * feat(proxy): ttl-tier-detect extension + ttl-management auto-upgrade (#97) Port preload.mjs:1815-1828 in-payload TTL tier detection to the proxy pipeline. Adds a new ttl-tier-detect extension at order 75 that scans body.system and body.messages[*].content[*] for any cache_control.ttl ="5m" and stashes ctx.meta._ttlTier. Order 75 sits before every extension that mutates cache_control (fresh-session-sort at 250, cache-control-normalize at 400, messages-cache-breakpoint at 410), so the signal survives downstream strips. ttl-management at order 500 now reads ctx.meta._ttlTier and applies preload's formula: ttlValue === "5m" || detectedTier === "5m" ? "5m" : "1h". Auto-detection upgrades effective 1h to 5m, never the reverse, never overrides explicit env "none". Closes the regression where users on CC v2.1.113+ silently injected mismatched TTL markers after Q5h saturation, which caused 1h-after-5m processing-order rejection and cache misses. Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com> * test(proxy): TTL tier detection — unit + pipeline-level coverage (#97) 22 new tests across three files mapping to directive tests #1-#22: - test/proxy-ttl-tier-detect.test.mjs (#1-#11): unit tests on detectExistingTier and the extension's onRequest hook (purity, idempotency, no body mutation). - test/proxy-ttl-management.test.mjs (#12-#17): consumer behavior — env=5m wins, env=none suppresses, env=1h upgrades to 5m on detected, subagent path, no overwrite of existing ttl. - test/proxy-ttl-tier-pipeline.test.mjs (#18-#22): pipeline-level integration via loadExtensions + runOnRequest, asserting end-state observables across the real extension order. Includes: #18 cache-control-normalize regression (user-message marker stripped) #19 fresh-session-sort regression (relocatable <skills> block stripped) #20 negative case (pure-1h payload) #21 env=none precedence #22 lead-flagged auto-upgrade (env=1h + detected=5m) Suite: 676 → 698 passing, +22 net. Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com> * docs: codex implementation review of PR #100 (TTL tier detection) * test: tighten pipeline #18 geometry + #19 assertion (Codex impl review) #18 was misconstructed: the only ttl=5m marker sat on the last block, which cache-control-normalize then re-applied to the same block — so a naive implementation that scanned post-normalize would also pass. Move the marker to the FIRST block of a user message whose LAST block has no cache_control on input. Now normalize strips at one position and re-applies the canonical at a different one, and the test only passes if detection ran pre-strip (i.e., the order-75 rewire works). #19 now asserts the relocated <skills> block has no cache_control on output, providing observable evidence that fresh-session-sort destructured the field per fresh-session-sort.mjs:140/:164 and the detection at order 75 is what saved the signal. Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com> * docs: codex impl re-review of PR #100 (TTL tier detection) --------- Co-authored-by: vsits-codex-review-agent[bot] <279859562+vsits-codex-review-agent[bot]@users.noreply.github.com> Co-authored-by: Claude Opus 4.7 <noreply@anthropic.com>
vsits-proxy-builder Bot
added a commit
that referenced
this pull request
May 5, 2026
) cache-telemetry rewrite: - Resolve session id from x-claude-code-session-id (canonical), with fallbacks to x-session-id and x-anthropic-session-id. - Apply canonical sessionFilename(rawId) rule: allowlist [A-Za-z0-9_-]{1,128} for raw passthrough, else inv-<sha256(raw)[:16]>; null/empty → "unknown". Path-traversal-safe by construction. - Write split layout: - ~/.claude/quota-status/account.json (account-global facts; fresh on every response) - ~/.claude/quota-status/sessions/<filename>.json (per-session cache facts; only updated when that session requests) - Atomic writes: writeFileSync to .tmp.<pid>.<crypto.randomBytes(4)> then renameSync. No partial reads possible. - Legacy ~/.claude/quota-status.json deleted on first invocation per process (one-shot via module-state flag) — removes stale-artifact footgun for post-upgrade consumers. - TTL sweep on sessions/ only, throttled to 60s, configurable via CACHE_FIX_QUOTA_STATUS_TTL_DAYS (default 7). microcompact-stability: - Session-id fallback chain now includes x-claude-code-session-id ahead of legacy x-session-id and x-anthropic-session-id. Was returning null for most CC requests because the canonical header wasn't in the chain. Tests: - 22 new cache-telemetry tests covering filename rule (#11a-#11i), file-write happy path + fallbacks (#1-#4), two-session interleaving (#5), quota-only skip (#6), atomic write contract (#7), legacy cleanup (#7a-#7b), TTL sweep behavior (#8-#11). - 4 new microcompact tests covering the new fallback chain (#12-#15). Ref #104 Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
8 tasks
cnighswonger
pushed a commit
that referenced
this pull request
May 5, 2026
* directive: per-session quota-status files (#104) Replace proxy-global ~/.claude/quota-status.json with split account.json + per-session <session-id>.json, eliminating cross-session contamination on multi-agent hosts. Folds in microcompact-stability fallback-chain fix to recognise the canonical x-claude-code-session-id header. Ref #104 Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com> * directive: address Lead's review (#105) - Add legacy ~/.claude/quota-status.json cleanup on first invocation per process (Lead's should-fix #1) — removes the stale-artifact footgun for post-upgrade consumers that haven't migrated. - Switch atomic-write tmp suffix from Math.random() to crypto.randomBytes(4).toString('hex') (Lead's should-tighten #2) — collision-resistant if a future change introduces multiple writers. - Drop "or concurrent" framing in test #17; specify back-to-back with rationale (Lead's nit #3) — JS is single-threaded; back-to-back is the reliably-testable shape that exercises the same invariant. - Add tests #7a/#7b for legacy cleanup behaviour (one-shot per process, silent on absence). Ref #104 Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com> * review: capture Codex directive findings for PR 105 * directive: address Codex's blocker — define filename rule (#105) - Define canonical session-id-to-filename derivation rule: - Allowlist [A-Za-z0-9_-]{1,128} for raw passthrough; otherwise inv-<sha256(rawId)[:16]> for malformed/oversized inputs. - Empty/null → "unknown". - Both writer (cache-telemetry) and readers (tools/) must apply the same rule. - Restructure layout: per-session files live under ~/.claude/quota-status/sessions/, account stays at top level. The subdirectory split makes reserved-name collisions structurally impossible. - Add tests #11a–#11j for filename rule (UUID, alphanumeric, empty, path-traversal, length cap, hash determinism, reserved names, pipeline integration with malformed input). - Add T1–T5 smoke tests for tools/quota-statusline.sh (Codex's needs-attention #3). - Expand migration table to include README sweep + tracked-issues docs (Codex's needs-attention #2). - Soften llm-relay external citation, add locally-verifiable corroboration (Codex's needs-attention #1). - Update acceptance criteria to cover the filename rule, doc sweep, and smoke test pass. Ref #104 Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com> * directive: normalize all paths to the sessions/ subdirectory layout (#105) Codex re-review caught that the design section adopted ~/.claude/quota-status/sessions/<filename>.json but stale references to the old root-level layout still appeared in: - CHANGELOG snippet (intro paragraph + ### Changed entry) - Tests #1-#5 (per-session file paths) - Sweep test #8 (stub directory + sweep boundary) - Sweep tests #9-#11 (per-session file location + account.json carve-out) - Test #11j (self-contradiction about whether account.json is written) - Acceptance bullet #1 All references now consistently describe the sessions/ subdirectory layout. Tests #8-#11 explicitly call out account.json living at the parent directory and being untouched by the sweep. Test #11j clarified that account.json IS expected to be written; the path-traversal-safety assertion is about no files appearing OUTSIDE ~/.claude/quota-status/sessions/. Ref #104 Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com> * review: capture Codex PR 105 directive re-review * directive: address Codex re-review findings (#105) - Replace literal NUL byte in test #11d with the textual escape \0, restoring the directive file to plain UTF-8 text. Standard tooling (rg, grep, file) was treating it as binary because of the embedded NUL — defeating the purpose of including the test sample at all. - Update llm-relay citation path: src/llm_relay/proxy/proxy.py is the canonical location on cnighswonger/llm-relay (Codex now has read access to that repo and verified). Also strengthens the framing — citation is now mechanically verified rather than just "Lead said so." Ref #104 Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com> * review: approve quota-status directive rereview2 * feat: per-session quota-status files + microcompact session-id fix (#104) cache-telemetry rewrite: - Resolve session id from x-claude-code-session-id (canonical), with fallbacks to x-session-id and x-anthropic-session-id. - Apply canonical sessionFilename(rawId) rule: allowlist [A-Za-z0-9_-]{1,128} for raw passthrough, else inv-<sha256(raw)[:16]>; null/empty → "unknown". Path-traversal-safe by construction. - Write split layout: - ~/.claude/quota-status/account.json (account-global facts; fresh on every response) - ~/.claude/quota-status/sessions/<filename>.json (per-session cache facts; only updated when that session requests) - Atomic writes: writeFileSync to .tmp.<pid>.<crypto.randomBytes(4)> then renameSync. No partial reads possible. - Legacy ~/.claude/quota-status.json deleted on first invocation per process (one-shot via module-state flag) — removes stale-artifact footgun for post-upgrade consumers. - TTL sweep on sessions/ only, throttled to 60s, configurable via CACHE_FIX_QUOTA_STATUS_TTL_DAYS (default 7). microcompact-stability: - Session-id fallback chain now includes x-claude-code-session-id ahead of legacy x-session-id and x-anthropic-session-id. Was returning null for most CC requests because the canonical header wasn't in the chain. Tests: - 22 new cache-telemetry tests covering filename rule (#11a-#11i), file-write happy path + fallbacks (#1-#4), two-session interleaving (#5), quota-only skip (#6), atomic write contract (#7), legacy cleanup (#7a-#7b), TTL sweep behavior (#8-#11). - 4 new microcompact tests covering the new fallback chain (#12-#15). Ref #104 Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com> * feat: migrate shipped tools + pipeline integration tests (#104) Tools migration to per-session quota-status layout: - tools/quota-statusline.sh: now reads CC's hook-stdin session_id, derives the per-session filename via the canonical rule (inline Python reimplementation of sessionFilename()), and reads ~/.claude/quota-status/account.json + sessions/<filename>.json. Falls back gracefully on missing session_id (quota only, no TTL block) and missing per-session file (warming-state aware). - tools/cache-test.sh: snapshot_cache helper now reads the most-recent per-session file in ~/.claude/quota-status/sessions/ (each one-shot CC invocation generates its own session_id, so latest mtime = the call we just made). The directive's "swap QUOTA_FILE → account.json" prescription would have lost the cache.* fields the script needs; reading the latest session file preserves them correctly. - tools/cross-version-cache-test.sh: account.json for the global Q5h read (the four spots in the script that read five_hour.pct). Tests: - New test/quota-statusline-smoke.test.mjs covers T1-T5 (UUID happy path, missing session_id fallback, warming-state, all-files-missing clean exit, malformed session_id reading the hashed filename). - New test/proxy-quota-status-pipeline.test.mjs covers the integration tests #16 (end-to-end happy path), #17 (two-session interleaving), and #11j (path-traversal safety) by driving the full extension pipeline from loadExtensions() through onResponseStart + onStreamEvent. Full suite: 698 → 732 tests, all passing. Ref #104 Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com> * docs: update README/translations + CHANGELOG for per-session quota-status (#104) - README.md, README.zh.md, README.ko.md: update three references each. (1) extension table description for `cache-telemetry` reflects the split account+sessions layout. (2) status-line section explains the per-session split for proxy mode and notes preload mode keeps the legacy single-file path. (3) monitoring section disambiguates between the two paths. - CHANGELOG.md: new ### Changed entry under [Unreleased] flagging the breaking path change with full migration context, the filename-rule shape, and the TTL/sweep env knob. ### Fixed entry for the microcompact session-id fallback chain. ### Tests entry for the 698 → 732 count. Ref #104 Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com> * review: capture PR 105 implementation findings * fix: address Codex implementation-review findings (#105) Blocking finding — quota-statusline.sh filename-rule consistency: The writer (cache-telemetry.mjs:sessionFilename) maps null/undefined/""/ whitespace-only ids to 'unknown' via the canonical rule. The shell reader was using `sess_id = stdin_data.get('session_id') or ''` which short-circuits for null and "" (skipping the per-session read entirely) but works for whitespace-only (which becomes a non-empty string and flows through session_filename). That asymmetry meant the writer/reader contract wasn't identical for null/empty inputs. Fix: pass the raw stdin value (including null/empty) directly into session_filename and always attempt to read sessions/<filename>.json. The "file doesn't exist" fallback already covers the "no sessions/unknown.json on disk" case gracefully — statusline shows account-only just like before, but for the right reason (file missing) instead of the wrong one (rule short-circuit). Test additions: - T2a covers null, "", " ", and "\t\n" inputs all reading sessions/unknown.json when it exists. Locks in the contract symmetry. Doc-sweep gaps (Codex's needs-attention): - docs/monitoring.md: quota-tracking and peak-hour-detection sections now describe the proxy/preload split and the per-session layout. - docs/guia-pt-br.md: debug snippet shows account.json as the proxy path and notes preload.json as legacy. Test count: 732 → 733. Ref #104 Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com> * docs: extension-impact-guide cache-telemetry path (#105) Codex's implementation re-review flagged this as a non-blocking new doc finding at docs/extension-impact-guide.md:84 — stale single-file path remained after the per-session sweep. Updated to describe the new split layout. Ref #104 Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com> * review: approve PR 105 implementation rereview --------- Co-authored-by: vsits-proxy-builder[bot] <279815601+vsits-proxy-builder[bot]@users.noreply.github.com> Co-authored-by: Claude Opus 4.7 <noreply@anthropic.com> Co-authored-by: vsits-codex-review-agent[bot] <279859562+vsits-codex-review-agent[bot]@users.noreply.github.com>
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
The suggested wrapper script wasn't playing nice with nvm because of all the relative paths.
Use
npm rootto make sure we're always executing from where the global version is installed.