@wy-ai-labs/logbus
v0.1.0
Published
In-memory log ring buffer with level/source/model filters and secret masking that never stores prompts or raw credentials; redaction helpers (maskSecrets, redact, sanitizeError)
Downloads
159
Maintainers
Readme
@wy-ai-labs/logbus
In-memory log ring buffer with level/source/model filters and secret masking that never stores a prompt or a raw credential — plus the redaction helpers (
maskSecrets,redact,sanitizeError) behind it.
Part of the wy-ai-labs parts monorepo (packages/logbus) · contract v1 · no Python twin
Install
npm install @wy-ai-labs/logbus # Node ≥22.11, ESM only (import — no require)30-second usage
import { createLogBus, maskSecrets, sanitizeError, CONTRACT_VERSION } from '@wy-ai-labs/logbus';
const bus = createLogBus({ capacity: 800 }); // ring buffer: oldest entry dropped first
const stop = bus.subscribe((e) => console.error(`[${e.source}] ${e.level} ${e.message}`)); // entries arrive already masked
bus.log('info', 'llm', 'request', { model: 'local-model', prompt: 'Summarise this file for me', maxTokens: 512 });
bus.log('error', 'llm', 'upstream 401: Authorization: Bearer abcdefghijklmnop rejected');
bus.log('info', 'llm', 'response', { model: 'local-model', finishReason: 'length', completionTokens: 512 });
console.log(CONTRACT_VERSION, bus.list({ level: 'warn' }).map((e) => e.message));
// 1 [ 'upstream 401: Authorization: Bearer abcd… rejected', 'response' ] ← finish=length was raised to warn
console.log(bus.list({ source: 'llm' })[0].meta.prompt); // { chars: 26, lines: 1, sha256: '…' } — never the text
console.log(bus.list({ limit: 1 })[0].meta); // { model: 'local-model', finishReason: 'length', completionTokens: 512, truncated: true }
console.log(maskSecrets('api_key=sk-1234abcd5678&user=bob')); // api_key=sk-1…&user=bob
console.log(sanitizeError(new Error('token=abcdefghij failed')).message); // token=abcd… failed
stop();Runs as-is, no endpoint needed. The bus never prints anything itself — subscribe to forward entries to a console, a file or an HTTP endpoint; what you forward is what was stored (masked, frozen, JSON.stringify-able).
Contract
Public API, invariants and error model are fixed in CONTRACT.md; the tests in test/ are the contract suite (one test per numbered invariant). Three invariants to know before depending on this part:
- No raw secret survives —
messagegoes throughmaskSecrets,metathroughredact; nothing a subscriber,list()ortoJSON()returns contains a Bearer/Basic token,sk-…/nvapi-…/gh*_…/AKIA…/xox*-…key,api_key= | token= | password= …value, Authorization header, URL credential or knownsecretsvalue. Masking keeps 4 characters +…and is idempotent. - Prompts are never stored —
meta.prompt,meta.messages,meta.stdout,meta.stderr(configurable, at any depth) are replaced by{ chars, lines, sha256 }summaries. - Error text is never truncated — a 5 000-character upstream error is stored in full (only credentials inside it are masked);
finishReason: 'length'is surfaced as at leastwarnwithmeta.truncated = true.
An incompatible change bumps CONTRACT_VERSION and the major version together (CONTRACT.md → Compatibility).
Mined from
Extracted from two private source repositories — LLM_GATEWAY (module server/logbus.mjs, its scripts/check-log-detail.mjs gate and the masking assertions in test/) and CodeReviewWar (server/llm/vendor/logbus.mjs, scripts/agents/lib/redaction.mjs with its tests, shared/review-contracts.ts#redactAuth with its test) — developed 2026-07-13 – 2026-08-19, generalized and re-tested for publication. What was kept, generalized and stripped: PROVENANCE.md.
Used by
| Client | Role of this part there |
|---|---|
| llm-gateway (blueprint desktop-tray-service, planned) | per-provider server log view (/logs?source=…), secret masking, finish=length warnings |
| code-review-war (blueprint desktop-review-app, planned) | in-process log bus for the review pipeline; redact / maskSecrets for agent scripts and GitHub error paths |
| ark (blueprint desktop-rag-workbench, planned) | runtime diagnostics without prompt or key leakage |
| parts llm-adapters, updater-core (planned) | log sink dependency |
Dependencies & budget
- Runtime dependencies: 0 (budget 0) — enforced by
scripts/check-budget.mjs. - Allowed: other
@wy-ai-labs/*parts, pinned as caret ranges from the registry. Never a client, neverfile:/link:/ git URLs /../. - No private host, model id or key as a default: the bus has no endpoint, no file and no transport — it holds entries in memory and hands them to subscribers;
source/modelvalues are whatever the caller logs.
Gates
| Command | What | When |
|---|---|---|
| npm test | contract suite (node:test), offline, seconds | every save |
| npm run gates:core | dependency budget + independence + engines.node + tests | before every commit / PR |
| npm run gates:full | everything above | nightly / before release |
CI only calls these scripts (wy-ai-labs/.github → node-gates.yml). Releases: Keep a Changelog + npm publish --provenance.
License
MIT © 2026 waneekim
한국어 요약
- @wy-ai-labs/logbus — 레벨/소스/모델 필터를 갖춘 메모리 로그 링 버퍼. 메시지는
maskSecrets, meta는redact를 거치므로 원문 자격증명이 저장·구독·직렬화 어디에도 남지 않고, 프롬프트(prompt/messages/stdout/stderr)는 본문 대신{ chars, lines, sha256 }요약만 남으며, 오류 본문은 절대 자르지 않습니다(finishReason: 'length'는 warn으로 승격). 공개 API·불변식·오류 모델은 CONTRACT.md에 고정되어 있고, 테스트가 곧 계약 스위트입니다. - 설치
npm install @wy-ai-labs/logbus(Node ≥22, ESM). 런타임 의존성 0, 다른 part에만 핀 버전으로 의존, 사설 호스트 기본값 없음. - 비공개 저장소
LLM_GATEWAY·CodeReviewWar에서 추출·일반화했습니다(PROVENANCE.md). 커밋 전npm run gates:core.
