mirror of
https://github.com/langgenius/dify.git
synced 2026-06-01 13:00:48 -04:00
69 lines
2.4 KiB
TypeScript
69 lines
2.4 KiB
TypeScript
import type { ServerVersionResponse } from '@dify/contracts/api/openapi/types.gen'
|
|
import type { NudgeStore } from '../cache/nudge-store.js'
|
|
import { colorScheme } from '../sys/io/color.js'
|
|
import { difyCompat, evaluateCompat } from './compat.js'
|
|
|
|
// Formats whose stdout is structured data (json/yaml) or a single name token —
|
|
// any stderr banner from us would pollute machine parsing. Default text format
|
|
// (the empty string) intentionally falls through and is allowed to warn.
|
|
const SUPPRESSED_FORMATS: ReadonlySet<string> = new Set(['json', 'yaml', 'name'])
|
|
|
|
export type NudgeDeps = {
|
|
readonly store: NudgeStore
|
|
// /openapi/v1/_version is intentionally unauthenticated (mirrors _health),
|
|
// so the probe does not need a bearer.
|
|
readonly probe: (host: string) => Promise<ServerVersionResponse>
|
|
readonly emit: (line: string) => void
|
|
readonly isTty: boolean
|
|
readonly format: string
|
|
readonly clientVersion: string
|
|
readonly color?: boolean
|
|
readonly now?: () => Date
|
|
}
|
|
|
|
// Public guarantee: never throws. Every internal failure is silenced so the
|
|
// calling authed command continues regardless of probe / disk errors.
|
|
//
|
|
// Order matters: cheap suppression checks (format, TTY, throttle window) run
|
|
// before any I/O so the happy path costs nothing in steady state.
|
|
export async function maybeNudgeCompat(host: string, deps: NudgeDeps): Promise<void> {
|
|
try {
|
|
if (!deps.isTty)
|
|
return
|
|
if (SUPPRESSED_FORMATS.has(deps.format))
|
|
return
|
|
if (!deps.store.canWarn(host, deps.now?.()))
|
|
return
|
|
|
|
let server: ServerVersionResponse
|
|
try {
|
|
server = await deps.probe(host)
|
|
}
|
|
catch {
|
|
return
|
|
}
|
|
|
|
const verdict = evaluateCompat(server.version)
|
|
if (verdict.status !== 'unsupported')
|
|
return
|
|
|
|
deps.emit(formatBanner(deps.clientVersion, server.version, deps.color === true))
|
|
await deps.store.markWarned(host, deps.now?.()).catch(() => {
|
|
// disk failure must not propagate; the user already saw the banner.
|
|
})
|
|
}
|
|
catch {
|
|
// belt-and-braces: any unexpected throw must not affect the business command
|
|
}
|
|
}
|
|
|
|
function formatBanner(clientVersion: string, serverVersion: string, color: boolean): string {
|
|
const { yellow } = colorScheme(color)
|
|
const { minDify, maxDify } = difyCompat
|
|
const line
|
|
= `warning: difyctl ${clientVersion} may be incompatible with server `
|
|
+ `${serverVersion} (tested: ${minDify}..${maxDify}). `
|
|
+ 'Run `difyctl version` for details.'
|
|
return `${yellow(line)}\n`
|
|
}
|