Documentation
¶
Index ¶
- Constants
- Variables
- func ExitCodeForCategory(cat errs.Category) int
- func ExitCodeOf(err error) int
- func ExtractItems(data interface{}) []interface{}
- func FindArrayField(data map[string]interface{}) string
- func FormatAsCSV(w io.Writer, data interface{})
- func FormatAsCSVPaginated(w io.Writer, data interface{}, isFirstPage bool)
- func FormatAsTable(w io.Writer, data interface{})
- func FormatAsTablePaginated(w io.Writer, data interface{}, isFirstPage bool)
- func FormatValue(w io.Writer, data interface{}, format Format)
- func GetNotice() map[string]interface{}
- func JqFilter(w io.Writer, data interface{}, expr string) error
- func JqFilterRaw(w io.Writer, data interface{}, expr string) error
- func PrintError(w io.Writer, msg string)
- func PrintJson(w io.Writer, data interface{})
- func PrintNdjson(w io.Writer, data interface{})
- func PrintSuccess(w io.Writer, msg string)
- func PrintTable(w io.Writer, rows []map[string]interface{})
- func StartSpinner(w io.Writer, enabled bool, label string) func()
- func SuccessEnvelopeData(result interface{}) interface{}
- func ValidateJqExpression(expr string) error
- func ValidateJqFlags(jqExpr, outputFlag, format string) error
- func WriteAlertWarning(w io.Writer, alert *extcs.Alert) error
- func WriteCSV(w io.Writer, data interface{}) error
- func WriteCSVPaginated(w io.Writer, data interface{}, isFirstPage bool) error
- func WriteFormatted(w io.Writer, data interface{}, format Format) error
- func WriteJSON(w io.Writer, data interface{}) error
- func WriteNDJSON(w io.Writer, data interface{}) error
- func WriteSuccessEnvelope(data interface{}, opts SuccessEnvelopeOptions) error
- func WriteTable(w io.Writer, data interface{}) error
- func WriteTablePaginated(w io.Writer, data interface{}, isFirstPage bool) error
- func WriteTypedErrorEnvelope(w io.Writer, err error, identity string) bool
- type BareError
- type EmitOptions
- type Emitter
- type EmitterConfig
- type Envelope
- type Format
- type Meta
- type NoticeProvider
- type PaginatedFormatter
- type PaginationMeta
- type PartialFailureError
- type PrettyRenderer
- type ScanResult
- type StreamOptions
- type SuccessEnvelopeOptions
Constants ¶
const ( Dim = "\033[2m" Bold = "\033[1m" Yellow = "\033[33m" Cyan = "\033[36m" Red = "\033[31m" Green = "\033[32m" Reset = "\033[0m" )
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.
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 // "Wrong app credentials" code from the LEGACY TAT endpoint // (/open-apis/auth/v3/tenant_access_token/internal returns 10014, "app secret // invalid", instead of 99991543). Since the OAuth v3 migration the CLI mints // TAT via accounts/oauth/v3/token and reports this as the OAuth invalid_client // error, so it no longer emits 10014 itself; the constant + codemeta mapping // are retained as a defensive fallback should 10014 still arrive. 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 the typed envelope preserves Problem.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.
Variables ¶
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 ExitCodeForCategory ¶ added in v1.0.41
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
ExitCodeOf returns the shell exit code for any error.
- typed errors (*errs.PermissionError, *errs.APIError, *errs.ConfigError, *errs.AuthenticationError, ...) → routed by Category
- *PartialFailureError / *BareError signals → their own Code field
- untyped → ExitInternal
func ExtractItems ¶
func ExtractItems(data interface{}) []interface{}
ExtractItems extracts the data array from a response. It tries two strategies in order:
- Lark API envelope: result["data"][arrayField] (e.g. {"code":0,"data":{"items":[…]}})
- Direct map: result[arrayField] (e.g. {"members":[…],"total":5})
If data is already a plain []interface{}, it is returned as-is.
func FindArrayField ¶
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 ¶
FormatAsCSV formats data as CSV (with header) and writes it to w.
func FormatAsCSVPaginated ¶
FormatAsCSVPaginated formats data as CSV with pagination awareness. When isFirstPage is true, outputs the header row; otherwise only data rows.
func FormatAsTable ¶
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 ¶
FormatAsTablePaginated formats data as a table with pagination awareness. When isFirstPage is true, outputs the header; otherwise only data rows.
func FormatValue ¶
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
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
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 PrintNdjson ¶
PrintNdjson prints data as NDJSON (Newline Delimited JSON) to w.
func PrintSuccess ¶
PrintSuccess prints a success message to w.
func PrintTable ¶
PrintTable prints rows as a table to w. Delegates to FormatAsTable for flattening, column union, and width handling.
func StartSpinner ¶ added in v1.0.61
StartSpinner renders a braille spinner with an elapsed-seconds counter to w until the returned stop() is called, e.g.:
⠹ Publishing dev → main... 3s
It is meant for slow operations (long polls, first-time provisioning) so the user sees the CLI is alive. Always write to STDERR (w = IO().ErrOut) so the animation never pollutes stdout — the JSON/pretty result stays clean.
When enabled is false (stderr is not a TTY: pipes, CI, captured output) it is a no-op returning a no-op stop, so non-interactive runs emit nothing. Gate on the stderr-TTY check (IOStreams.StderrIsTerminal), not the output format: the spinner is stderr-only and self-clears, so it is shown in JSON mode too.
stop() clears the spinner line, restores the cursor, and blocks until the render goroutine has finished — so callers can safely write the result to stdout/stderr immediately after. Call stop() BEFORE printing the result, and it is safe to call more than once (e.g. an explicit call plus a defer).
func SuccessEnvelopeData ¶ added in v1.0.56
func SuccessEnvelopeData(result interface{}) interface{}
SuccessEnvelopeData extracts the business payload for the standard success envelope from a Lark API response. Outer code/msg fields are transport protocol details and are intentionally not exposed as business data.
func ValidateJqExpression ¶ added in v1.0.3
ValidateJqExpression checks whether a jq expression is syntactically valid.
func ValidateJqFlags ¶ added in v1.0.3
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
WriteAlertWarning writes a human-readable content-safety warning to w. Used by non-JSON output paths (pretty, table, csv) in warn mode.
func WriteCSVPaginated ¶ added in v1.0.74
WriteCSVPaginated formats data as CSV and returns marshal or write errors.
func WriteFormatted ¶ added in v1.0.74
WriteFormatted formats a single response and returns marshal or write errors.
func WriteJSON ¶ added in v1.0.74
WriteJSON writes data as formatted JSON to w and returns marshal or write errors.
func WriteNDJSON ¶ added in v1.0.74
WriteNDJSON writes data as NDJSON and returns marshal or write errors.
func WriteSuccessEnvelope ¶ added in v1.0.56
func WriteSuccessEnvelope(data interface{}, opts SuccessEnvelopeOptions) error
WriteSuccessEnvelope emits the standard success envelope used by shortcuts. JSON output carries content-safety alerts inside the envelope. When jq is applied, the alert may be filtered away, so warn mode also writes stderr.
func WriteTable ¶ added in v1.0.74
WriteTable formats data as a table and returns marshal or write errors.
func WriteTablePaginated ¶ added in v1.0.74
WriteTablePaginated formats data as a table and returns marshal or write errors.
func WriteTypedErrorEnvelope ¶ added in v1.0.41
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:
- Serialize the envelope into an in-memory buffer. If serialization fails, return false so the dispatcher handles it via its signal / usage-error branches; nothing is written to w.
- 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 (the dispatcher then handles it via its signal / usage-error branches) or when JSON encoding itself failed.
Types ¶
type BareError ¶ added in v1.0.56
type BareError struct{ Code int }
BareError is the silent-exit signal for commands whose stdout already carries the complete answer and that only need the matching exit code without a stderr envelope. Two cases use it: a predicate writing its yes/no JSON (e.g. `auth check` exiting non-zero on a no-token state), and a command emitting its own structured result envelope under `--json` (e.g. `update`). Deliberately outside the typed-envelope contract.
type EmitOptions ¶ added in v1.0.74
type EmitOptions struct {
Raw bool
Meta *Meta
Format string
JQ string
DryRun bool
Pretty PrettyRenderer
JQSafetyWarning bool
}
EmitOptions describes one result's wire representation.
The format contract is explicit: JSON (including the empty default) uses an Envelope. Pretty and table render business data plus a human pagination summary when supplied; csv and ndjson keep stdout as naked records and put pagination metadata on the diagnostics stream. JQ takes precedence over Format and filters the JSON Envelope. Raw affects only JSON envelope encoding and jq's complex-value encoding.
JQSafetyWarning preserves the legacy difference between RuntimeContext.emit (false) and WriteSuccessEnvelope (true) until their callers are migrated.
type Emitter ¶ added in v1.0.74
type Emitter struct {
// contains filtered or unexported fields
}
Emitter owns all command-scoped output dependencies and pagination state. It deliberately has no dependency on client or cmdutil.
func NewEmitter ¶ added in v1.0.74
func NewEmitter(config EmitterConfig) *Emitter
NewEmitter constructs a command-scoped output emitter.
func (*Emitter) PartialFailure ¶ added in v1.0.74
func (e *Emitter) PartialFailure(data interface{}, opts EmitOptions) error
PartialFailure emits a multi-status result whose envelope honestly reports ok:false. It is the typed counterpart to Success for batch operations where some items failed but the per-item outcomes are the primary stdout output. Like the legacy OutPartialFailure it produces only the JSON/jq envelope; the caller owns the non-zero exit signal, keeping the Emitter free of exit semantics.
func (*Emitter) StreamPage ¶ added in v1.0.74
func (e *Emitter) StreamPage(data interface{}, opts StreamOptions) error
StreamPage scans and emits one page while retaining table/csv columns from the first page. Streamed output carries page items directly, so it takes a StreamOptions (format + optional pretty renderer) rather than the full EmitOptions: ok/meta/dry-run/jq all need the aggregated result and are the caller's pagination-layer responsibility, not a per-page concern. Excluding jq from the type makes "jq requires aggregated output" a compile-time fact instead of a runtime rejection.
func (*Emitter) Success ¶ added in v1.0.74
func (e *Emitter) Success(data interface{}, opts EmitOptions) error
Success scans and emits one command result by composing the package's leaf primitives. JSON and jq use the standard envelope; record formats keep their stdout payload free of envelope metadata.
type EmitterConfig ¶ added in v1.0.74
type EmitterConfig struct {
Out io.Writer
ErrOut io.Writer
CommandPath string
Identity string
ColorEnabled bool
NoticeProvider NoticeProvider
}
EmitterConfig contains command-scoped dependencies. A command constructs one Emitter and reuses it for its success result or streamed pages.
type Envelope ¶
type Envelope struct {
OK bool `json:"ok"`
Identity string `json:"identity,omitempty"`
DryRun bool `json:"dry_run,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 Format ¶
type Format int
Format represents an output format type.
func ParseFormat ¶
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.
type Meta ¶
type Meta struct {
Count int `json:"count,omitempty"`
Rollback string `json:"rollback,omitempty"`
Pagination *PaginationMeta `json:"pagination,omitempty"`
}
Meta carries optional metadata in envelope responses.
type NoticeProvider ¶ added in v1.0.74
type NoticeProvider func() map[string]interface{}
NoticeProvider supplies the notice attached to a structured envelope. The provider is captured by an Emitter so emission never reads the global PendingNotice hook implicitly.
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.
func (*PaginatedFormatter) WritePage ¶ added in v1.0.74
func (pf *PaginatedFormatter) WritePage(data interface{}) error
WritePage formats one page of items and returns marshal or write errors.
type PaginationMeta ¶ added in v1.0.82
type PaginationMeta struct {
// Complete is true only when the server's exhausted state was observed.
Complete bool `json:"complete"`
// Pages counts successful API pages included in this result.
Pages int `json:"pages"`
// Items counts records after command-level filtering and enrichment.
Items int `json:"items"`
// NextToken is the cursor at which an incomplete result can resume.
NextToken string `json:"next_token,omitempty"`
}
PaginationMeta reports how a paginated read ended.
It lives in the envelope's meta rather than in the business data because a stop reason is not part of the resource: writing it into data both pollutes the payload and forces the caller to tell an API field apart from one the CLI synthesised. Complete plus NextToken is the whole story — a run either exhausted the endpoint or stopped at --page-limit with somewhere to resume — so there is no separate stop_reason string to keep in sync.
type PartialFailureError ¶ added in v1.0.47
type PartialFailureError struct {
Code int
}
PartialFailureError is the exit signal for a batch / multi-status command that has already written an ok:false result envelope to stdout. The per-item outcomes are the primary, machine-readable output and live on stdout, so the dispatcher sets only the exit code and writes nothing to stderr.
It is deliberately distinct from ErrBare (the stdout-carries-the-answer silent-exit signal) so that contract stays narrow, and from a typed *errs.XxxError (which owns the stderr error envelope): a partial failure is a result, not an error envelope.
func PartialFailure ¶ added in v1.0.47
func PartialFailure(code int) *PartialFailureError
PartialFailure builds the partial-failure exit signal with the given code.
func (*PartialFailureError) Error ¶ added in v1.0.47
func (e *PartialFailureError) Error() string
type PrettyRenderer ¶ added in v1.0.74
PrettyRenderer writes the human-readable representation of one result. colorEnabled is the terminal capability captured when the Emitter is built.
type ScanResult ¶ added in v1.0.18
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.
type StreamOptions ¶ added in v1.0.74
type StreamOptions struct {
Format string
Pretty PrettyRenderer
}
StreamOptions describes one streamed page's wire representation. Streaming carries page items directly, so it deliberately exposes only the fields that affect a single page: the format and, for pretty, its renderer. It has no OK/Meta/DryRun/JQ — an ok:false envelope, metadata, dry-run, and jq all need the aggregated result, which the caller's pagination layer owns before it streams pages.