* feat(cli): add central error translation layer (PR1)
Introduce server/internal/cli/errors.go, a single user-facing error
translation layer that collapses raw transport errors, HTTP status
errors, and internal verb-wrapped chains into clear, localized messages.
- ErrorKind classification (network timeout/DNS/refused/TLS/offline,
401/403/404/409/400+422/429/5xx, unknown)
- NetworkError wraps transport errors and strips the raw URL from the
user-facing message; classifyNetworkError categorizes via errors.As/Is
with string fallbacks
- HTTPError.Kind() maps status codes onto ErrorKind
- FormatError: bilingual output (English default, auto-switch to Chinese
on a zh LC_ALL/LC_MESSAGES/LANG locale), validation errors surface the
server message; --debug / MULTICA_DEBUG appends the full raw chain
- ExitCodeFor: tiered exit codes (network=2, auth=3, 404=4, validation=5,
other=1)
- client.go: default HTTP timeout 15s -> 30s, overridable via
MULTICA_HTTP_TIMEOUT; wrap every transport Do() error as *NetworkError
- main.go: route errors through FormatError + ExitCodeFor, add persistent
--debug flag
Unit tests cover every ErrorKind, classification, language detection,
exit codes, server-message extraction, and timeout parsing.
Refs MUL-3104. PR1 of 3; PR2/PR3 (status-code copy refinement and
per-command customization) follow separately.
Co-authored-by: multica-agent <github@multica.ai>
* fix(cli): address review — unify command timeouts and classify all helper errors
Must-fix 1: command-level contexts no longer truncate MULTICA_HTTP_TIMEOUT.
Added cli.APITimeout/AtLeastAPITimeout/APIContext (budget = transport timeout
+ small grace, honoring MULTICA_HTTP_TIMEOUT) and replaced the hardcoded 15s
context.WithTimeout in every API command (14 files, 92 sites) with
cli.APIContext. The issue-create/comment path now uses APITimeout() with a
60s floor for attachment uploads.
Must-fix 2: all API helpers now return *HTTPError on status >= 400. Added a
shared newHTTPError(method, path, resp) and routed GetJSON, GetJSONWithHeaders,
PostJSON, PutJSON, PatchJSON, DeleteJSON, DeleteJSONWithBody, UploadFile,
UploadFileWithURL, DownloadFile (and HealthCheck) through it, so issue
update/status/metadata (PUT), comment list (GetJSONWithHeaders), project/label/
comment delete (DELETE) and agent/workspace/autopilot update (PUT/PATCH) all
get HTTPError.Kind() classification, friendly copy, and the tiered exit code
instead of the raw string + exit 1.
Tests: new errors_integration_test.go drives the real helpers against a fake
server and asserts FormatError copy + ExitCodeFor for 401/403/404/422/500
across all 10 helpers, plus a slow-server test proving the command context
does not cancel before the transport timeout. Updated the UploadFileWithURL
assertion to check for *HTTPError.
Refs MUL-3104, PR #3892.
Co-authored-by: multica-agent <github@multica.ai>
* fix(cli): make remaining fixed-timeout API commands honor MULTICA_HTTP_TIMEOUT
Closes out the timeout work: the last API command paths still used a
hardcoded context deadline that capped MULTICA_HTTP_TIMEOUT. Converted them
to cli.AtLeastAPITimeout(<original floor>) so the env override scales them up
while preserving each original lower bound:
- cmd_autopilot.go autopilot trigger 30s -> AtLeastAPITimeout(30s)
- cmd_attachment.go attachment download 60s -> AtLeastAPITimeout(60s)
- cmd_agent.go avatar upload 60s -> AtLeastAPITimeout(60s)
- cmd_skill.go skill import / search 60s -> AtLeastAPITimeout(60s)
- cmd_runtime.go runtime update 150s -> AtLeastAPITimeout(150s)
- cmd_login.go workspace-creation poll 10s -> AtLeastAPITimeout(10s)
The login poll keeps a short 10s floor to stay responsive within its 5-minute
loop, but it is NOT a silent exception: AtLeastAPITimeout means it still scales
with MULTICA_HTTP_TIMEOUT. Documented in code and covered by a new subtest in
TestAPITimeoutRespectsEnv.
Refs MUL-3104, PR #3892.
Co-authored-by: multica-agent <github@multica.ai>
* style(cli): gofmt cmd_attachment.go to unblock backend CI
Co-authored-by: multica-agent <github@multica.ai>
---------
Co-authored-by: multica-agent <github@multica.ai>