From 4f61353dc2035ce6bd755120ef44ce8f85464958 Mon Sep 17 00:00:00 2001 From: L1nSn0w Date: Mon, 22 Jun 2026 12:53:58 +0800 Subject: [PATCH] fix(cli): align difyctl help text with actual flags and error envelope (#37728) --- cli/src/help/contract.test.ts | 26 ++++++++++++++++++++++++++ cli/src/help/contract.ts | 2 +- cli/src/help/topics.test.ts | 4 ++-- cli/src/help/topics.ts | 4 ++-- 4 files changed, 31 insertions(+), 5 deletions(-) create mode 100644 cli/src/help/contract.test.ts diff --git a/cli/src/help/contract.test.ts b/cli/src/help/contract.test.ts new file mode 100644 index 00000000000..272e1ff8d88 --- /dev/null +++ b/cli/src/help/contract.test.ts @@ -0,0 +1,26 @@ +import type { ErrorBody } from '@dify/contracts/api/openapi/types.gen' +import { describe, expect, it } from 'vitest' +import { HttpClientError, newError } from '@/errors/base' +import { ErrorCode } from '@/errors/codes' +import { CONTRACT } from './contract' + +describe('errorEnvelope contract', () => { + // Guard against the documented shape drifting from the real envelope: build an + // error with every optional field populated and assert each JSON key it emits + // is named in the contract string. Adding/removing an envelope field without + // updating the doc fails here. + it('documents every key the real JSON envelope can emit', () => { + const server: ErrorBody = { code: 'app_unavailable', message: 'gone', status: 404 } + const err = HttpClientError.from(newError(ErrorCode.Server4xxOther, 'boom')) + .withHint('do x') + .withRequest('GET', 'https://api.dify.ai/v1/me') + .withHttpStatus(404) + .withRawResponse('{"x":1}') + .withServerError(server) + + const env = err.toEnvelope() + + for (const key of Object.keys(env.error)) + expect(CONTRACT.errorEnvelope.shape).toContain(`"${key}"`) + }) +}) diff --git a/cli/src/help/contract.ts b/cli/src/help/contract.ts index 1d68da8b268..d4be7209280 100644 --- a/cli/src/help/contract.ts +++ b/cli/src/help/contract.ts @@ -38,7 +38,7 @@ export const CONTRACT: Contract = { description: 'On failure the error goes to stderr. Under -o json/yaml it is a structured envelope; otherwise a human line.', shape: - '{ "error": { "code": string, "message": string, "hint"?: string, "http_status"?: number, "request"?: string } }', + '{ "error": { "code": string, "message": string, "hint"?: string, "http_status"?: number, "method"?: string, "url"?: string, "raw_response"?: string, "server"?: object } }', }, hitl: { description: diff --git a/cli/src/help/topics.test.ts b/cli/src/help/topics.test.ts index f5b2d1843e9..5a326895035 100644 --- a/cli/src/help/topics.test.ts +++ b/cli/src/help/topics.test.ts @@ -50,10 +50,10 @@ describe('agent topic', () => { }) describe('external topic', () => { - it('mentions external bearer prefix and login flag', () => { + it('mentions external bearer prefix and DIFY_TOKEN onboarding', () => { const out = render('external') expect(out).toContain('dfoe_') - expect(out).toContain('--external') + expect(out).toContain('export DIFY_TOKEN') expect(out).toContain('DIFY_TOKEN') }) diff --git a/cli/src/help/topics.ts b/cli/src/help/topics.ts index 3da5c0f8dfc..6ccfd1044ee 100644 --- a/cli/src/help/topics.ts +++ b/cli/src/help/topics.ts @@ -37,8 +37,8 @@ const EXTERNAL_HELP_TEXT = `difyctl: external-SSO bearer onboarding smaller dataset: 1. Acquire a token through your SSO provider (out of band). - 2. Hand it to the CLI: - difyctl auth login --external --token "$DIFY_TOKEN" + 2. Hand it to the CLI via the DIFY_TOKEN environment variable: + export DIFY_TOKEN="" 3. List apps your subject is permitted to invoke: difyctl get app