mirror of
https://github.com/abhigyanpatwari/GitNexus.git
synced 2026-09-20 00:11:37 +00:00
Some checks are pending
CodeQL / Analyze (javascript-typescript) (push) Waiting to run
CodeQL / Analyze (python) (push) Waiting to run
Gitleaks / gitleaks (push) Waiting to run
Publish / Classify release event (push) Waiting to run
Publish / RC guard (marker + release-PR skip) (push) Blocked by required conditions
Publish / ci (push) Blocked by required conditions
Publish / Publish to npm (push) Blocked by required conditions
Publish / Build & Push RC Docker images (push) Blocked by required conditions
Scorecard / Scorecard analysis (push) Waiting to run
Trivy Image Scan / Trivy (gitnexus-cli) (push) Waiting to run
Trivy Image Scan / Trivy (gitnexus-web) (push) Waiting to run
134 lines
4.5 KiB
TypeScript
134 lines
4.5 KiB
TypeScript
/**
|
|
* CLI message helpers — for user-facing banners, error guidance, and
|
|
* recovery hints emitted by `gitnexus` subcommands.
|
|
*
|
|
* These functions write **plain text** directly to `process.stderr` AND
|
|
* tee a structured pino record through the singleton `logger`. Plain text
|
|
* preserves the human-readable contract for users running `gitnexus`
|
|
* interactively, redirecting to a file, or piping to `cat`/`grep`. The
|
|
* structured tee keeps log aggregators happy.
|
|
*
|
|
* **Use these for:**
|
|
* - User-facing banners ("Server listening on http://...:N")
|
|
* - Validation errors ("--worker-timeout must be at least 1 second")
|
|
* - Recovery hints ("Suggestions: 1. Clear the npm cache, 2. ...")
|
|
* - One-line user notices ("No indexed repositories found.")
|
|
*
|
|
* **Do NOT use these for:**
|
|
* - Internal diagnostics (worker progress, retry counts, telemetry)
|
|
* — use `logger.info`/`warn`/`error` directly. Internal logs only
|
|
* need structured fields, not double-output to stderr.
|
|
* - High-volume hot paths — every `cliMessage` call writes twice (raw
|
|
* + structured). Acceptable for user-facing messages, wasteful for
|
|
* ingestion pipeline events.
|
|
*
|
|
* Design note: stderr is the right channel even for non-error messages
|
|
* because GitNexus CLI tools (`query`, `cypher`, `impact`) emit JSON
|
|
* data on stdout for piping (`gitnexus query | jq`). User banners on
|
|
* stdout would corrupt that pipeline.
|
|
*/
|
|
import { logger } from '../core/logger.js';
|
|
import { t, type CliMessageKey, type CliMessageVars } from './i18n/index.js';
|
|
|
|
/**
|
|
* String-literal union of all `recoveryHint` tags emitted by the CLI.
|
|
*
|
|
* Centralized so a new recovery branch added in `analyze.ts` cannot land
|
|
* without updating this union — TypeScript will reject the unknown literal
|
|
* passed via `cliError({ recoveryHint: '...' })`. To add a new hint:
|
|
* 1. Add the tag string to this union.
|
|
* 2. Pass it as the `recoveryHint` field at the relevant `cliError`
|
|
* call site.
|
|
*
|
|
* Consumers can import this type to narrow log-record `recoveryHint`
|
|
* fields without restating the literal list.
|
|
*/
|
|
export type RecoveryHint =
|
|
| 'wal-corruption'
|
|
| 'wal-checkpoint-threshold'
|
|
| 'lbug-wipe-failed'
|
|
| 'lbug-page-size'
|
|
| 'heap-oom-respawn'
|
|
| 'native-worker-abort'
|
|
| 'hf-endpoint-unreachable'
|
|
| 'http-embedding-endpoint-error'
|
|
| 'embedding-dims-invalid'
|
|
| 'local-embedding-unsupported'
|
|
| 'local-embedding-stack-missing'
|
|
| 'large-repo'
|
|
| 'npm-resolution'
|
|
| 'module-not-found'
|
|
| 'gitnexusrc-invalid'
|
|
| 'default-branch-invalid';
|
|
|
|
/**
|
|
* Common shape for the optional structured-field bag passed to
|
|
* `cliError`/`cliWarn`/`cliInfo`. Typed so the `recoveryHint` slot is
|
|
* checked against the {@link RecoveryHint} union.
|
|
*/
|
|
export interface CliMessageFields extends Record<string, unknown> {
|
|
recoveryHint?: RecoveryHint;
|
|
}
|
|
|
|
function writeStderr(msg: string): void {
|
|
// Direct write — bypassing `console.*` so it cannot be intercepted by
|
|
// progress-bar redirection (see `cli/analyze.ts:barLog`) or other
|
|
// routing. The structured tee below still goes through the logger so
|
|
// log aggregation works either way.
|
|
process.stderr.write(msg.endsWith('\n') ? msg : msg + '\n');
|
|
}
|
|
|
|
/**
|
|
* User-facing informational message. Use for banners, listening URLs,
|
|
* and any message the user expects to read in plain text.
|
|
*/
|
|
export function cliInfo(msg: string, fields?: CliMessageFields): void {
|
|
writeStderr(msg);
|
|
logger.info(fields ?? {}, msg);
|
|
}
|
|
|
|
/**
|
|
* Key-based informational message. Keeps the legacy string API intact while
|
|
* allowing commands to opt into localized user-facing stderr output.
|
|
*/
|
|
export function cliInfoKey(
|
|
key: CliMessageKey,
|
|
vars?: CliMessageVars,
|
|
fields?: Record<string, unknown>,
|
|
): void {
|
|
cliInfo(t(key, vars), fields);
|
|
}
|
|
|
|
/**
|
|
* User-facing warning. Operator-actionable but non-fatal — `cliWarn`
|
|
* indicates the command can still proceed in some form.
|
|
*/
|
|
export function cliWarn(msg: string, fields?: CliMessageFields): void {
|
|
writeStderr(msg);
|
|
logger.warn(fields ?? {}, msg);
|
|
}
|
|
|
|
export function cliWarnKey(
|
|
key: CliMessageKey,
|
|
vars?: CliMessageVars,
|
|
fields?: Record<string, unknown>,
|
|
): void {
|
|
cliWarn(t(key, vars), fields);
|
|
}
|
|
|
|
/**
|
|
* User-facing error. Indicates the command cannot proceed; usually
|
|
* paired with a non-zero exit code at the call site.
|
|
*/
|
|
export function cliError(msg: string, fields?: CliMessageFields): void {
|
|
writeStderr(msg);
|
|
logger.error(fields ?? {}, msg);
|
|
}
|
|
|
|
export function cliErrorKey(
|
|
key: CliMessageKey,
|
|
vars?: CliMessageVars,
|
|
fields?: Record<string, unknown>,
|
|
): void {
|
|
cliError(t(key, vars), fields);
|
|
}
|