output

package
v1.0.45 Latest Latest
Warning

This package is not in the latest version of its module.

Go to latest
Published: Jun 1, 2026 License: MIT Imports: 19 Imported by: 0

Documentation

Index

Constants

View Source
const (
	Dim    = "\033[2m"
	Bold   = "\033[1m"
	Yellow = "\033[33m"
	Cyan   = "\033[36m"
	Red    = "\033[31m"
	Green  = "\033[32m"
	Reset  = "\033[0m"
)
View Source
const (
	ExitOK                   = 0  // 成功
	ExitAPI                  = 1  // API / 通用错误(含 permission、not_found、conflict、rate_limit)
	ExitValidation           = 2  // 参数校验失败
	ExitAuth                 = 3  // 认证失败(token 无效 / 过期),或登录成功但请求 scopes 未全部授予
	ExitNetwork              = 4  // 网络错误(连接超时、DNS 解析失败等)
	ExitInternal             = 5  // 内部错误(不应发生)
	ExitContentSafety        = 6  // content safety violation (block mode)
	ExitConfirmationRequired = 10 // 高风险操作需要 --yes 确认(agent 协议信号)
)

Fine-grained error types (permission, not_found, rate_limit, etc.) are communicated via the JSON error envelope's "type" field, not via exit codes.

View Source
const (
	// Auth: token missing / invalid / expired.
	LarkErrTokenMissing = 99991661 // Authorization header missing or empty
	LarkErrTokenBadFmt  = 99991671 // token format error (must start with "t-" or "u-")
	LarkErrTokenInvalid = 99991668 // user_access_token invalid or expired
	LarkErrATInvalid    = 99991663 // access_token invalid (generic)
	LarkErrTokenExpired = 99991677 // user_access_token expired, refresh to obtain a new one

	// Permission: scope not granted.
	LarkErrAppScopeNotEnabled    = 99991672 // app has not applied for the required API scope
	LarkErrTokenNoPermission     = 99991676 // token lacks the required scope
	LarkErrUserScopeInsufficient = 99991679 // user has not granted the required scope
	LarkErrUserNotAuthorized     = 230027   // user not authorized

	// App credential / status.
	LarkErrAppCredInvalid  = 99991543 // app_id or app_secret is incorrect (Open API)
	LarkErrAppNotInUse     = 99991662 // app is disabled in this tenant
	LarkErrAppUnauthorized = 99991673 // app status unavailable; check installation

	// TAT-endpoint variant of the "wrong app credentials" condition.
	// /open-apis/auth/v3/tenant_access_token/internal returns code 10014
	// ("app secret invalid") instead of 99991543 when the secret is wrong.
	LarkErrTATInvalidSecret = 10014

	// Rate limit.
	LarkErrRateLimit = 99991400 // request frequency limit exceeded

	// Refresh token errors (authn service).
	LarkErrRefreshInvalid     = 20026 // refresh_token invalid or v1 format
	LarkErrRefreshExpired     = 20037 // refresh_token expired
	LarkErrRefreshRevoked     = 20064 // refresh_token revoked
	LarkErrRefreshAlreadyUsed = 20073 // refresh_token already consumed (single-use rotation)

	// Drive shortcut / cross-space constraints.
	LarkErrDriveResourceContention = 1061045 // resource contention occurred, please retry
	LarkErrDriveCrossTenantUnit    = 1064510 // cross tenant and unit not support
	LarkErrDriveCrossBrand         = 1064511 // cross brand not support

	// Wiki write-path lock contention (e.g. concurrent wiki +node-create under the
	// same parent). Server-side write lock; transient, safe to retry with backoff.
	LarkErrWikiLockContention = 131009

	// Sheets float image: width/height/offset out of range or invalid.
	LarkErrSheetsFloatImageInvalidDims = 1310246

	// Drive permission apply: per-user-per-document submission limit (5/day) reached.
	LarkErrDrivePermApplyRateLimit = 1063006
	// Drive permission apply: request is not applicable for this document
	// (e.g. the document is configured to disallow access requests, or the
	// caller already holds the requested permission, or the target type does
	// not accept apply operations).
	LarkErrDrivePermApplyNotApplicable = 1063007

	// IM resource ownership mismatch.
	LarkErrOwnershipMismatch = 231205

	// Mail send: account / mailbox-level failures returned by
	// POST /open-apis/mail/v1/user_mailboxes/:user_mailbox_id/drafts/:draft_id/send.
	// Mail v1 uses service-scoped 123xxxx codes; keep the full upstream code
	// because ErrAPI preserves Detail.Code exactly as returned by the server.
	// These codes indicate the entire batch will keep failing identically and
	// are consumed by shortcuts/mail.isFatalSendErr to abort early.
	LarkErrMailboxNotFound        = 1234013 // mailbox not found or not active
	LarkErrMailSendQuotaUser      = 1236007 // user daily send count exceeded
	LarkErrMailSendQuotaUserExt   = 1236008 // user daily external recipient count exceeded
	LarkErrMailSendQuotaTenantExt = 1236009 // tenant daily external recipient count exceeded
	LarkErrMailQuota              = 1236010 // mail quota limit
	LarkErrTenantStorageLimit     = 1236013 // tenant storage limit exceeded
)

Lark API generic error code constants. ref: https://open.feishu.cn/document/server-docs/api-call-guide/generic-error-code

Kept as exported identifiers because external shortcut packages reference them by name (e.g. LarkErrOwnershipMismatch). The canonical Category / Subtype / Retryable metadata for each code lives in internal/errclass and must remain the single source of truth — ClassifyLarkError below resolves classification through errclass.LookupCodeMeta.

Variables

View Source
var PendingNotice func() map[string]interface{}

PendingNotice, if set, returns system-level notices to inject as the "_notice" field in JSON output envelopes. Set by cmd/root.go. Returns nil when there is nothing to report.

Functions

func ClassifyLarkError deprecated

func ClassifyLarkError(code int, msg string) (int, string, string)

ClassifyLarkError maps a Lark API error code + message to the legacy (exitCode, errType, hint) tuple consumed by the *ExitError path.

Classification is sourced from errclass.LookupCodeMeta (the single source of truth). exitCode follows legacyExitCode below, which differs from ExitCodeForCategory in two preserved-legacy quirks: Authorization + permission subtypes return ExitAPI (legacy treated "permission" as exit 1), and Config returns ExitAuth (legacy bundled "check app_id/secret" under exit 3). errType maps to a legacy short string; unknown subtypes fall back to "api_error". Unknown codes classify as (ExitAPI, "api_error", "").

Deprecated: route Lark API responses through errclass.BuildAPIError, which emits a typed *errs.XxxError with Category, Subtype, and identity-aware extension fields populated at the source.

func ExitCodeForCategory added in v1.0.41

func ExitCodeForCategory(cat errs.Category) int

ExitCodeForCategory maps an errs.Category to the shell exit code. Multiple categories may share an exit code (Authentication / Authorization / Config all map to 3), so the relationship is many-to-one.

func ExitCodeOf added in v1.0.41

func ExitCodeOf(err error) int

ExitCodeOf returns the shell exit code for any error.

  • typed errors (*errs.PermissionError, *errs.APIError, ...) → routed by Category
  • legacy *output.ExitError → uses its own Code field
  • *core.ConfigError → reaches the dispatcher as a legacy *output.ExitError via cmd/root asExitError (stage 1); the typed promotion path through internal/errcompat.PromoteConfigError is reserved for stage 2+.
  • untyped → ExitInternal

func ExtractItems

func ExtractItems(data interface{}) []interface{}

ExtractItems extracts the data array from a response. It tries two strategies in order:

  1. Lark API envelope: result["data"][arrayField] (e.g. {"code":0,"data":{"items":[…]}})
  2. Direct map: result[arrayField] (e.g. {"members":[…],"total":5})

If data is already a plain []interface{}, it is returned as-is.

func FindArrayField

func FindArrayField(data map[string]interface{}) string

FindArrayField finds the primary array field in a response's data object. It first checks knownArrayFields in priority order, then falls back to the lexicographically smallest unknown array field for deterministic results.

func FormatAsCSV

func FormatAsCSV(w io.Writer, data interface{})

FormatAsCSV formats data as CSV (with header) and writes it to w.

func FormatAsCSVPaginated

func FormatAsCSVPaginated(w io.Writer, data interface{}, isFirstPage bool)

FormatAsCSVPaginated formats data as CSV with pagination awareness. When isFirstPage is true, outputs the header row; otherwise only data rows.

func FormatAsTable

func FormatAsTable(w io.Writer, data interface{})

FormatAsTable formats data as a table and writes it to w.

  • []interface{} (array of objects) → header + separator + rows
  • map[string]interface{} (single object) → key-value two-column table
  • empty array → "(empty)"

func FormatAsTablePaginated

func FormatAsTablePaginated(w io.Writer, data interface{}, isFirstPage bool)

FormatAsTablePaginated formats data as a table with pagination awareness. When isFirstPage is true, outputs the header; otherwise only data rows.

func FormatValue

func FormatValue(w io.Writer, data interface{}, format Format)

FormatValue formats a single response and writes it to w.

func GetNotice added in v1.0.1

func GetNotice() map[string]interface{}

GetNotice returns the current pending notice for struct-based callers. Returns nil when there is nothing to report.

func JqFilter added in v1.0.3

func JqFilter(w io.Writer, data interface{}, expr string) error

JqFilter applies a jq expression to data and writes the results to w. Scalar values are printed raw (no quotes for strings), matching jq -r behavior. Complex values (maps, arrays) are printed as indented JSON with Go's default HTML escaping (<, >, & → <, >, &).

func JqFilterRaw added in v1.0.19

func JqFilterRaw(w io.Writer, data interface{}, expr string) error

JqFilterRaw is like JqFilter but disables HTML escaping when re-marshaling complex jq results. Use it alongside OutRaw when the upstream envelope carries XML/HTML content that must survive --jq '.data.document' style projections without getting mangled into < escapes.

func MarkRaw

func MarkRaw(err error) error

MarkRaw sets Raw=true on an ExitError so that the dispatcher skips enrichment (e.g. enrichPermissionError, enrichMissingScopeError) and preserves the upstream message verbatim. Returns the original error unchanged if it is not (or does not wrap) an ExitError.

Used by `cmd/api` and other "passthrough" call sites where the caller wants the original Lark response wording rather than the enriched message/hint variant.

func PrintError

func PrintError(w io.Writer, msg string)

PrintError prints an error message to w.

func PrintJson

func PrintJson(w io.Writer, data interface{})

PrintJson prints data as formatted JSON to w.

func PrintNdjson

func PrintNdjson(w io.Writer, data interface{})

PrintNdjson prints data as NDJSON (Newline Delimited JSON) to w.

func PrintSuccess

func PrintSuccess(w io.Writer, msg string)

PrintSuccess prints a success message to w.

func PrintTable

func PrintTable(w io.Writer, rows []map[string]interface{})

PrintTable prints rows as a table to w. Delegates to FormatAsTable for flattening, column union, and width handling.

func ValidateJqExpression added in v1.0.3

func ValidateJqExpression(expr string) error

ValidateJqExpression checks whether a jq expression is syntactically valid.

func ValidateJqFlags added in v1.0.3

func ValidateJqFlags(jqExpr, outputFlag, format string) error

ValidateJqFlags checks --jq flag compatibility with --output and --format flags, and validates the jq expression syntax. Returns nil if jqExpr is empty.

func WriteAlertWarning added in v1.0.18

func WriteAlertWarning(w io.Writer, alert *extcs.Alert)

WriteAlertWarning writes a human-readable content-safety warning to w. Used by non-JSON output paths (pretty, table, csv) in warn mode.

func WriteErrorEnvelope deprecated

func WriteErrorEnvelope(w io.Writer, err *ExitError, identity string)

WriteErrorEnvelope writes a JSON error envelope for the given ExitError to w.

Deprecated: legacy envelope writer. Typed errors are dispatched by cmd/root.go through WriteTypedErrorEnvelope.

func WriteTypedErrorEnvelope added in v1.0.41

func WriteTypedErrorEnvelope(w io.Writer, err error, identity string) bool

WriteTypedErrorEnvelope writes the JSON error envelope for a typed error. Each typed error owns its wire shape via its own struct tags: Problem fields are promoted to the top level through embedding, and extension fields (MissingScopes, ChallengeURL, etc.) sit alongside as siblings — not inside a `detail` sub-object.

Two-stage write:

  1. Serialize the envelope into an in-memory buffer. If serialization fails, return false so the dispatcher falls back to the legacy envelope path; nothing is written to w.
  2. Best-effort write of the serialized bytes to w. A partial write is accepted (return value still true): the typed exit code has already been determined upstream by handleRootError calling ExitCodeOf(err) before this writer runs, so a torn envelope on stderr must not downgrade the caller's typed exit (3/4/6/10) to plain 1. Consumers parse-or-skip on malformed JSON.

Returns true when err was a typed error and serialization succeeded. Returns false only when err carries no Problem (caller should fall back to WriteErrorEnvelope) or when JSON encoding itself failed.

Types

type Envelope

type Envelope struct {
	OK                 bool                   `json:"ok"`
	Identity           string                 `json:"identity,omitempty"`
	Data               interface{}            `json:"data,omitempty"`
	Meta               *Meta                  `json:"meta,omitempty"`
	ContentSafetyAlert interface{}            `json:"_content_safety_alert,omitempty"`
	Notice             map[string]interface{} `json:"_notice,omitempty"`
}

Envelope is the standard success response wrapper.

type ErrDetail deprecated

type ErrDetail struct {
	Type       string      `json:"type"`
	Code       int         `json:"code,omitempty"`
	Message    string      `json:"message"`
	Hint       string      `json:"hint,omitempty"`
	ConsoleURL string      `json:"console_url,omitempty"`
	Risk       *RiskDetail `json:"risk,omitempty"`
	Detail     interface{} `json:"detail,omitempty"`
}

ErrDetail describes a structured error.

Deprecated: ErrDetail belongs to the legacy *output.ExitError surface that predates the typed error contract introduced by errs/. New code MUST NOT use it — typed errs.* structs embed errs.Problem and own their wire shape via JSON tags (Category, Subtype, Hint, etc. promote to the top level). This struct is retained only while existing *ExitError call sites are migrated; it will be removed once they have moved to the typed surface.

type ErrorEnvelope deprecated

type ErrorEnvelope struct {
	OK       bool                   `json:"ok"`
	Identity string                 `json:"identity,omitempty"`
	Error    *ErrDetail             `json:"error"`
	Meta     *Meta                  `json:"meta,omitempty"`
	Notice   map[string]interface{} `json:"_notice,omitempty"`
}

ErrorEnvelope is the standard error response wrapper.

Deprecated: ErrorEnvelope belongs to the legacy *output.ExitError surface that predates the typed error contract introduced by errs/. New code MUST NOT use it — the typed envelope shape is owned by internal/output.WriteTypedErrorEnvelope which marshals typed errs.* errors directly via JSON reflection (no wrapper struct needed). This struct is retained only while existing *ExitError call sites are migrated; it will be removed once they have moved to the typed surface.

type ExitError deprecated

type ExitError struct {
	Code   int
	Detail *ErrDetail
	Err    error
	Raw    bool // when true, the dispatcher skips enrichment (e.g. enrichPermissionError) and preserves the original error detail
}

ExitError is a structured error that carries an exit code and optional detail. It is propagated up the call chain and handled by main.go to produce a JSON error envelope on stderr and the correct exit code.

Deprecated: legacy error type. Return a typed *errs.XxxError instead (see errs/types.go).

func ErrAPI deprecated

func ErrAPI(larkCode int, msg string, detail any) *ExitError

ErrAPI creates an API ExitError using ClassifyLarkError. For permission errors, uses a concise message; the raw API response is preserved in Detail.

Deprecated: route through errclass.BuildAPIError, which emits typed *errs.PermissionError / *errs.AuthenticationError / etc. with MissingScopes, ConsoleURL, and Identity at the source.

func ErrAuth

func ErrAuth(format string, args ...any) *ExitError

ErrAuth creates an authentication ExitError (exit 3, wire type "auth").

New code should construct a typed *errs.AuthenticationError directly; the typed envelope emits the canonical `type: "authentication"`. Migrating an existing call site flips a user-visible wire field.

func ErrBare

func ErrBare(code int) *ExitError

ErrBare creates an ExitError with only an exit code and no envelope. The predicate-command silent-exit signal: stdout has already been written and the caller wants the matching exit code without a stderr envelope (e.g. `auth check` emitting its JSON result and then exiting non-zero on a no-token state). Outside the typed-envelope contract.

func ErrNetwork

func ErrNetwork(format string, args ...any) *ExitError

ErrNetwork creates a network ExitError (exit 4, wire type "network"). The legacy envelope emits only `type`+`message`; for `subtype` ("transport" / "timeout" / "tls" / "dns") and retryable hint extension fields, construct a typed *errs.NetworkError directly.

func ErrValidation

func ErrValidation(format string, args ...any) *ExitError

ErrValidation creates a validation ExitError (exit 2, wire type "validation"). The legacy envelope emits only `type`+`message`; for `subtype` / `param` extension fields, construct a typed *errs.ValidationError directly.

func ErrWithHint deprecated

func ErrWithHint(code int, errType, msg, hint string) *ExitError

ErrWithHint creates an ExitError with a hint string.

Deprecated: construct a typed *errs.XxxError directly and set its Hint field; the typed envelope promotes Problem.Hint to the wire.

func Errorf deprecated

func Errorf(code int, errType, format string, args ...any) *ExitError

Errorf creates an ExitError with the given code, type, and formatted message.

Deprecated: construct a typed *errs.XxxError directly (e.g. errs.NewValidationError, errs.NewInternalError).

func (*ExitError) Error

func (e *ExitError) Error() string

func (*ExitError) Unwrap

func (e *ExitError) Unwrap() error

type Format

type Format int

Format represents an output format type.

const (
	FormatJSON Format = iota
	FormatNDJSON
	FormatTable
	FormatCSV
)

func ParseFormat

func ParseFormat(s string) (Format, bool)

ParseFormat parses a format string into a Format value. The second return value is false if the format string was not recognized, in which case FormatJSON is returned as default.

func (Format) String

func (f Format) String() string

String returns the string representation of a Format.

type Meta

type Meta struct {
	Count    int    `json:"count,omitempty"`
	Rollback string `json:"rollback,omitempty"`
}

Meta carries optional metadata in envelope responses.

type PaginatedFormatter

type PaginatedFormatter struct {
	W      io.Writer
	Format Format
	// contains filtered or unexported fields
}

PaginatedFormatter holds state across paginated calls to ensure consistent columns (table/csv use the first page's columns for all pages).

func NewPaginatedFormatter

func NewPaginatedFormatter(w io.Writer, format Format) *PaginatedFormatter

NewPaginatedFormatter creates a formatter that tracks pagination state.

func (*PaginatedFormatter) FormatPage

func (pf *PaginatedFormatter) FormatPage(data interface{})

FormatPage formats one page of items.

type RiskDetail deprecated added in v1.0.21

type RiskDetail struct {
	Level  string `json:"level"`
	Action string `json:"action"`
}

RiskDetail carries agent-protocol risk information alongside confirmation_required errors. Level is one of "read" | "write" | "high-risk-write". Action identifies the command for the agent (e.g. "mail +send", "drive.files.delete").

Deprecated: RiskDetail is reachable only via *output.ExitError.Detail.Risk, part of the legacy envelope surface that predates the typed error contract introduced by errs/. New code MUST NOT use it — confirmation-required signals belong on *errs.ConfirmationRequiredError (its own typed extension fields can carry agent-protocol metadata directly). This struct is retained only while existing *ExitError call sites are migrated; it will be removed once they have moved to the typed surface.

type ScanResult added in v1.0.18

type ScanResult struct {
	Alert    *extcs.Alert
	Blocked  bool
	BlockErr error
}

ScanResult holds the output of ScanForSafety.

func ScanForSafety added in v1.0.18

func ScanForSafety(cmdPath string, data any, errOut io.Writer) ScanResult

ScanForSafety runs content-safety scanning on the given data. cmdPath is the raw cobra CommandPath(). When MODE=off, no provider registered, or the command is not allowlisted, returns a zero ScanResult.

Jump to

Keyboard shortcuts

? : This menu
/ : Search site
f or F : Jump to
y or Y : Canonical URL