From 37d415d08146f6e7c4ebb628e09badc5013cf29f Mon Sep 17 00:00:00 2001 From: "haozhe.yang" Date: Thu, 11 Jun 2026 19:04:51 +0800 Subject: [PATCH] fix(server): use in-process pino-pretty stream to avoid worker transport startup failure - switch createServerLogger from pino transport target to in-process pretty stream\n- update changeset to cover @moonshot-ai/server\n- add test asserting pretty logger does not use ThreadStream\n- rename cli server test description --- .changeset/fix-pino-pretty-runtime.md | 1 + apps/kimi-code/test/cli/server/server.test.ts | 2 +- .../server/src/services/pinoLoggerService.ts | 23 +++++++++---------- packages/server/test/start.test.ts | 14 +++++++++++ 4 files changed, 27 insertions(+), 13 deletions(-) diff --git a/.changeset/fix-pino-pretty-runtime.md b/.changeset/fix-pino-pretty-runtime.md index 7e61e4ef5..416296da5 100644 --- a/.changeset/fix-pino-pretty-runtime.md +++ b/.changeset/fix-pino-pretty-runtime.md @@ -1,5 +1,6 @@ --- "@moonshot-ai/kimi-code": patch +"@moonshot-ai/server": patch --- Fix server startup from npm-installed CLI packages when pretty logging is enabled. diff --git a/apps/kimi-code/test/cli/server/server.test.ts b/apps/kimi-code/test/cli/server/server.test.ts index 0e1b0b072..296c7bb07 100644 --- a/apps/kimi-code/test/cli/server/server.test.ts +++ b/apps/kimi-code/test/cli/server/server.test.ts @@ -23,7 +23,7 @@ function makeProgram(): Command { } describe('kimi server', () => { - it('declares the pino pretty transport as a CLI runtime dependency', () => { + it('declares pino-pretty as a CLI runtime dependency', () => { const packageJson = JSON.parse( readFileSync(new URL('../../../package.json', import.meta.url), 'utf-8'), ) as { dependencies?: Record }; diff --git a/packages/server/src/services/pinoLoggerService.ts b/packages/server/src/services/pinoLoggerService.ts index 367365437..ee6a8f648 100644 --- a/packages/server/src/services/pinoLoggerService.ts +++ b/packages/server/src/services/pinoLoggerService.ts @@ -1,6 +1,7 @@ import { Disposable } from '@moonshot-ai/agent-core'; import { ILogService } from '@moonshot-ai/services'; import { pino, type Logger, type LoggerOptions } from 'pino'; +import prettyStream from 'pino-pretty'; export type ServerLogger = Logger; @@ -19,18 +20,16 @@ export function createServerLogger(opts: CreateLoggerOptions): ServerLogger { timestamp: pino.stdTimeFunctions.isoTime, }; if (pretty) { - return pino({ - ...base, - transport: { - target: 'pino-pretty', - options: { - colorize: true, - translateTime: 'SYS:HH:MM:ss.l o', - ignore: 'pid,hostname', - singleLine: false, - }, - }, - }); + return pino( + base, + prettyStream({ + colorize: true, + translateTime: 'SYS:HH:MM:ss.l o', + ignore: 'pid,hostname', + singleLine: false, + destination: process.stdout, + }), + ); } return pino(base); } diff --git a/packages/server/test/start.test.ts b/packages/server/test/start.test.ts index b7b2b611f..863b18eb7 100644 --- a/packages/server/test/start.test.ts +++ b/packages/server/test/start.test.ts @@ -38,6 +38,7 @@ import { ISessionClientsService, IWSBroadcastService, IWSGateway, + createServerLogger, startServer, type LockContents, type RunningServer, @@ -112,6 +113,19 @@ describe('startServer — lock + healthz smoke', () => { }); }); +describe('createServerLogger', () => { + it('uses an in-process pretty stream instead of pino worker transport', () => { + const logger = createServerLogger({ level: 'info', pretty: true }); + const streamSym = (pino as unknown as { symbols: { streamSym: symbol } }).symbols.streamSym; + const stream = logger[streamSym as keyof typeof logger] as unknown as NodeJS.WritableStream & { + constructor?: { name?: string }; + }; + + expect(stream.constructor?.name).not.toBe('ThreadStream'); + stream.end(); + }); +}); + describe('startServer — web assets', () => { it('serves web assets from the server root without shadowing API routes', async () => { const assetsDir = join(tmpDir, 'web-assets');