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)
- func WriteSuccessEnvelope(data interface{}, opts SuccessEnvelopeOptions) error
- func WriteTypedErrorEnvelope(w io.Writer, err error, identity string) bool
- type BareError
- type Envelope
- type Format
- type Meta
- type PaginatedFormatter
- type PartialFailureError
- type ScanResult
- 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 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 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 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 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 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 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 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.