fix(cli): color hints with magenta prefix and cyan values

This commit is contained in:
GareArc
2026-05-19 13:53:44 -07:00
parent e827aca154
commit 0bf64ca3f2
6 changed files with 27 additions and 19 deletions

View File

@ -1,6 +1,7 @@
import type { SseEvent } from '../../../../http/sse.js'
import type { RunContext, RunStrategy } from './index.js'
import { buildRunBody } from '../../../../api/app-run.js'
import { colorEnabled, colorScheme } from '../../../../io/color.js'
import { startSpinner } from '../../../../io/spinner.js'
import { extractThinkBlocks, stripThinkBlocks } from '../../../../io/think-filter.js'
import { chatConversationHint, newAppRunObject, RUN_MODES } from '../handlers.js'
@ -89,7 +90,8 @@ export class StreamingStructuredStrategy implements RunStrategy {
const respMode = typeof processedResp.mode === 'string' && processedResp.mode !== '' ? processedResp.mode : mode
deps.io.out.write(printFlags.toPrinter(format).print(newAppRunObject(respMode, processedResp)))
if (isText && CHAT_MODES.has(respMode)) {
const hint = chatConversationHint(processedResp)
const cs = colorScheme(colorEnabled(deps.io.isErrTTY))
const hint = chatConversationHint(processedResp, cs)
if (hint !== undefined)
deps.io.err.write(hint)
}

View File

@ -26,7 +26,7 @@ export class StreamingTextStrategy implements RunStrategy {
try {
const events = await ctx.runClient.runStream(opts.appId, body, { signal: ctrl.signal })
const sp = printFlags.toStreamPrinter(mode, ctx.think)
const sp = printFlags.toStreamPrinter(mode, ctx.think, deps.io.isErrTTY)
const dec = new TextDecoder()
for await (const ev of events) {
if (ev.name === 'ping')

View File

@ -62,8 +62,8 @@ describe('difyFileType', () => {
expect(difyFileType('notes.md')).toBe('document')
})
it('returns custom for unknown extension', () => {
expect(difyFileType('data.xyz')).toBe('custom')
it('returns document for unknown extension', () => {
expect(difyFileType('data.xyz')).toBe('document')
})
it('returns custom for no extension', () => {

View File

@ -1,3 +1,4 @@
import type { ColorScheme } from '../../../io/color.js'
import type { TextHandler } from '../../../printers/format-text.js'
export const RUN_MODES = {
@ -59,11 +60,11 @@ export const workflowTextHandler: TextHandler = {
},
}
export function chatConversationHint(resp: Record<string, unknown>): string | undefined {
export function chatConversationHint(resp: Record<string, unknown>, cs: ColorScheme): string | undefined {
const cid = pickString(resp, 'conversation_id')
if (cid === undefined || cid === '')
return undefined
return `hint: continue this conversation with --conversation ${cid}\n`
return `${cs.magenta('hint:')} continue this conversation with --conversation ${cs.cyan(cid)}\n`
}
function pickString(o: Record<string, unknown>, key: string): string | undefined {

View File

@ -21,7 +21,7 @@ export class AppRunPrintFlags extends CompositePrintFlags {
return [this.jsonYaml, this.text]
}
toStreamPrinter(mode: string, think = false): StreamPrinter {
return streamPrinterFor(mode, think)
toStreamPrinter(mode: string, think = false, isTTY = false): StreamPrinter {
return streamPrinterFor(mode, think, isTTY)
}
}

View File

@ -3,6 +3,7 @@ import type { StreamPrinter } from '../../../printers/stream-printer.js'
import type { HitlPausePayload } from './sse-collector.js'
import { newError } from '../../../errors/base.js'
import { ErrorCode } from '../../../errors/codes.js'
import { colorEnabled, colorScheme } from '../../../io/color.js'
import { ThinkChunkFilter } from '../../../io/think-filter.js'
import { RUN_MODES } from './handlers.js'
import { HitlPauseError } from './sse-collector.js'
@ -42,8 +43,10 @@ function handleCommonEvents(ev: SseEvent): boolean {
class ChatStreamPrinter implements StreamPrinter {
private convoId = ''
private readonly filter: ThinkChunkFilter
constructor(think: boolean) {
private readonly isTTY: boolean
constructor(think: boolean, isTTY = false) {
this.filter = new ThinkChunkFilter(think)
this.isTTY = isTTY
}
onEvent(out: NodeJS.WritableStream, errOut: NodeJS.WritableStream, ev: SseEvent): void {
@ -72,8 +75,10 @@ class ChatStreamPrinter implements StreamPrinter {
onEnd(out: NodeJS.WritableStream, errOut: NodeJS.WritableStream): void {
this.filter.flush(out, errOut)
out.write('\n')
if (this.convoId !== '')
errOut.write(`hint: continue this conversation with --conversation ${this.convoId}\n`)
if (this.convoId !== '') {
const cs = colorScheme(colorEnabled(this.isTTY))
errOut.write(`${cs.magenta('hint:')} continue this conversation with --conversation ${cs.cyan(this.convoId)}\n`)
}
}
}
@ -139,17 +144,17 @@ class WorkflowStreamPrinter implements StreamPrinter {
}
}
const FACTORIES: Record<string, (think: boolean) => StreamPrinter> = {
[RUN_MODES.Chat]: think => new ChatStreamPrinter(think),
[RUN_MODES.AdvancedChat]: think => new ChatStreamPrinter(think),
[RUN_MODES.AgentChat]: think => new ChatStreamPrinter(think),
[RUN_MODES.Completion]: think => new CompletionStreamPrinter(think),
[RUN_MODES.Workflow]: _think => new WorkflowStreamPrinter(),
const FACTORIES: Record<string, (think: boolean, isTTY: boolean) => StreamPrinter> = {
[RUN_MODES.Chat]: (think, isTTY) => new ChatStreamPrinter(think, isTTY),
[RUN_MODES.AdvancedChat]: (think, isTTY) => new ChatStreamPrinter(think, isTTY),
[RUN_MODES.AgentChat]: (think, isTTY) => new ChatStreamPrinter(think, isTTY),
[RUN_MODES.Completion]: (think, _isTTY) => new CompletionStreamPrinter(think),
[RUN_MODES.Workflow]: (_think, _isTTY) => new WorkflowStreamPrinter(),
}
export function streamPrinterFor(mode: string, think = false): StreamPrinter {
export function streamPrinterFor(mode: string, think = false, isTTY = false): StreamPrinter {
const f = FACTORIES[mode]
if (f === undefined)
throw newError(ErrorCode.Unknown, `unsupported streaming mode "${mode}"`)
return f(think)
return f(think, isTTY)
}