MCPcopy
hub / github.com/vectorize-io/hindsight / Logger

Class Logger

hindsight-integrations/opencode/src/logger.ts:43–100  ·  view source on GitHub ↗

Source from the content-addressed store, hash-verified

41const SERVICE = "hindsight";
42
43export class Logger {
44 private readonly client?: OpencodeLogClient;
45 private readonly debugEnabled: boolean;
46 private readonly silent: boolean;
47
48 constructor(options: LoggerOptions = {}) {
49 this.client = options.client;
50 this.debugEnabled = options.debug ?? false;
51 this.silent = options.silent ?? false;
52 }
53
54 private emit(level: LogLevel, message: string, extra?: Record<string, unknown>): void {
55 if (this.silent) return;
56
57 const app = this.client?.app;
58 if (app && typeof app.log === "function") {
59 try {
60 // IMPORTANT: call as a method on `app` so `this` is preserved.
61 // OpenCode's `app.log` is a class method that uses `this` internally;
62 // calling a detached reference (`const log = app.log; log(...)`) throws
63 // `this._client is undefined`, which would otherwise be swallowed below
64 // and produce no log at all.
65 const result = app.log({ body: { service: SERVICE, level, message, extra } });
66 // Fire-and-forget: a logging failure must never surface to OpenCode.
67 if (result && typeof (result as Promise<unknown>).then === "function") {
68 (result as Promise<unknown>).then(undefined, () => {});
69 }
70 return;
71 } catch {
72 // Fall through to the console fallback if app.log throws synchronously.
73 }
74 }
75
76 // Fallback when no OpenCode client is available (or app.log failed).
77 // OpenCode captures plugin console output into its logs, so this stays
78 // visible and TUI-safe.
79 const line = extra
80 ? `[Hindsight] ${message} ${JSON.stringify(extra)}`
81 : `[Hindsight] ${message}`;
82 console.error(line);
83 }
84
85 error(message: string, error?: unknown): void {
86 this.emit("error", message, error === undefined ? undefined : { error: errorToString(error) });
87 }
88
89 warn(message: string, extra?: Record<string, unknown>): void {
90 this.emit("warn", message, extra);
91 }
92
93 info(message: string, extra?: Record<string, unknown>): void {
94 this.emit("info", message, extra);
95 }
96
97 debug(message: string, extra?: Record<string, unknown>): void {
98 if (this.debugEnabled) this.emit("debug", message, extra);
99 }
100}

Callers

nothing calls this directly

Calls

no outgoing calls

Tested by

no test coverage detected