Skip to content

Feat/channels list show all and drop auth#78456

Merged
sliverp merged 5 commits intomainfrom
feat/channels-list-show-all-and-drop-auth
May 7, 2026
Merged

Feat/channels list show all and drop auth#78456
sliverp merged 5 commits intomainfrom
feat/channels-list-show-all-and-drop-auth

Conversation

@sliverp
Copy link
Copy Markdown
Member

@sliverp sliverp commented May 6, 2026

Summary

  • Problem: openclaw channels list was a catch-all: it mixed chat channels with model-provider auth profiles (OAuth + API keys) and a model-provider usage/quota snapshot, silently hid every channel without a configured account, and — even with a hypothetical --all — offered no way to discover the full set of channels an operator could configure. External catalog channels that happened to be installed on disk but not yet configured (e.g. WeCom after an experimental install) also disappeared from the listing because the read-only channel loader only activates channels that appear in user config.
  • Why it matters: channels is the CLI contract for discovering, configuring, and operating chat integrations. Operators kept asking channels add / channels login for a channel they had never heard of because channels list refused to advertise it until a config entry already existed; scripts were pulling a stale auth field out of the JSON payload that actually belonged to model-provider auth (reachable from openclaw models auth list); and every default channels list call fanned out to every configured model provider's billing/auth endpoint before printing anything, so a command that should be pure-local routinely added seconds of network latency and printed provider fetch errors under a channel-management heading.
  • What changed:
    • Removed the Auth providers (OAuth + API keys) text section and the auth field from the JSON payload. Model-provider auth now stays in openclaw models auth list, where it conceptually belongs.
    • Removed the model-provider usage/quota snapshot (loadProviderUsageSummary fan-out), the --no-usage flag, and the usage field from the JSON payload. Usage is now owned by openclaw status (overview) and openclaw models list (per-provider), which already render it consistently. The text output ends with a single static line pointing at those two commands so operators who expected usage know where it went.
    • Added a --all flag. Default output is unchanged (still only configured accounts). --all additionally surfaces bundled channels without a configured account, catalog channels that are not yet installed on disk, and catalog channels that are installed on disk but not yet configured.
    • Each row now renders three explicit status tags — installed / not installed, configured / not configured, enabled / disabled — sourced from the same isCatalogChannelInstalled probe used by openclaw onboard and channels add, so tags stay consistent across commands.
    • JSON payload gained an origin tag per channel (configured / available / installable) alongside an installed: boolean field so tooling can distinguish "user has set this up" from "user could set this up" without inference.
  • What did NOT change (scope boundary):
    • Default channels list row layout for configured channels (same per-row label, same account-id formatting, same token / bot / app / base / linked bits when present, same empty-state behavior except for a hint pointing at --all and the new one-line migration pointer replacing the former usage block).
    • channels add / channels login / channels logout / channels status / channels capabilities / channels resolve / channels remove behavior.
    • The read-only channel loader (listReadOnlyChannelPluginsForConfig), the catalog loader (listTrustedChannelPluginCatalogEntries), the installed-channel probe (isCatalogChannelInstalled), and the provider usage module (loadProviderUsageSummary / formatUsageReportLines). Only channels list stops consuming the latter; openclaw status / openclaw models list still do.

Change Type (select all)

  • Bug fix
  • Feature
  • Refactor required for the fix
  • Docs
  • Security hardening
  • Chore/infra

Scope (select all touched areas)

  • Gateway / orchestration
  • Skills / tool execution
  • Auth / tokens
  • Memory / storage
  • Integrations
  • API / contracts
  • UI / DX
  • CI/CD / infra

Linked Issue/PR

  • Closes #
  • Related #
  • This PR fixes a bug or regression

Regression / clean-up context:

  • A user reported WeCom disappearing from channels list --all even though @wecom/wecom-openclaw-plugin was installed on disk.
  • The listing also advertised model-provider auth profiles and ran a per-provider usage fetch under a chat-channel command; both were historical catch-all behavior from when channels list was the only operator overview surface, and both are already owned by dedicated commands (openclaw models auth list / openclaw status / openclaw models list).

Real behavior proof (required for external PRs)

  • Behavior or issue addressed: openclaw channels list conflated chat channels with model-provider auth profiles and a per-provider usage fetch, hid every channel without a configured account, and even with --all omitted catalog channels whose npm package was already on disk but had no config entry yet (WeCom-class regression).
  • Real environment tested: local OpenClaw 2026.5.6 build (branch HEAD 7a45871ef5, rebased on latest origin/main) on Linux, against ~/.openclaw/openclaw.json containing only a configured qqbot channel entry, no wecom config entry, and @wecom/wecom-openclaw-plugin installed on disk from a previous experimental install.
  • Exact steps or command run after this patch:
    1. pnpm openclaw channels list
    2. pnpm openclaw channels list --all
    3. pnpm openclaw channels list --json / pnpm openclaw channels list --all --json
    4. pnpm openclaw channels list --no-usage — expect "unknown option" (flag removed).
  • Evidence after fix:
    $ pnpm openclaw channels list
    🦞 OpenClaw 2026.5.6
    Chat channels:
    - QQ Bot default: installed, configured, enabled
    
    Model provider usage moved out of `channels list` — see `openclaw status` or `openclaw models list`.
    Docs: gateway/configuration
    
    $ pnpm openclaw channels list --all
    🦞 OpenClaw 2026.5.6
    Chat channels:
    - QQ Bot default: installed, configured, enabled
    - WeCom: installed, not configured, disabled             # (was missing before)
    - Telegram: not installed, not configured, disabled
    - WhatsApp: not installed, not configured, disabled
    - Discord: not installed, not configured, disabled
    - …
    
    Model provider usage moved out of `channels list` — see `openclaw status` or `openclaw models list`.
    Docs: gateway/configuration
    
    $ pnpm openclaw channels list --all --json
    {
      "chat": {
        "qqbot":    { "accounts": ["default"], "installed": true,  "origin": "configured"  },
        "wecom":    { "accounts": [],          "installed": true,  "origin": "available"   },
        "telegram": { "accounts": [],          "installed": false, "origin": "installable" },
        ...
      }
    }
    # No top-level "auth" or "usage" keys.
    
    $ pnpm openclaw channels list --no-usage
    error: unknown option '--no-usage'
    
    Unit regression: src/commands/channels.list.test.ts — 9 tests pass (WeCom catalog-installed-but-unconfigured regression is the 9th).
  • Observed result after fix:
    • Auth providers section gone from both text and JSON.
    • Model-provider usage fetch gone from the default path; no blocking provider-billing calls when running the command.
    • Default output unchanged for already-configured operators (modulo the removed auth/usage blocks and the one static migration pointer at the bottom).
    • --all now lists bundled-unconfigured + catalog-not-installed + catalog-installed-but-unconfigured rows, each with correct installed / configured / enabled tags.
    • WeCom (and any other catalog channel in the same state) no longer disappears.
  • What was not tested:
    • Full-volume run on deployments with dozens of installed catalog plugins (tested set was ~25 entries).
    • Interactive wizard flows from channels add / channels login — out of scope for channels list.
  • Before evidence (optional but encouraged):
    $ pnpm openclaw channels list --all    # before this PR
    Chat channels:
    - QQ Bot default: installed, configured, enabled
    - Feishu: not installed, not configured, not enabled
    - …
    - Telegram: not installed, not configured, not enabled
    - WhatsApp: not installed, not configured, not enabled
    
    Auth providers (OAuth + API keys):
    - openrouter:default (api_key)
    - openai-codex:default (oauth)
    - tencent-token-plan:default (api_key)
    - ...
    
    # Plus a per-provider "Usage" block fetched from provider billing
    # endpoints — each one a blocking network call before the command
    # returned.
    # WeCom was also missing entirely.
    

Root Cause (if applicable)

  • Root cause:
    1. Auth-providers-in-channels-list is a historical artifact: channels list was originally the only "operator overview" command and absorbed model-provider auth profiles before openclaw models auth list existed. It was never revisited after models auth list landed.
    2. The same catch-all history produced a model-provider usage/quota fetch appended under every invocation, with a --no-usage escape hatch whose only purpose was to turn off work that did not belong to the command. openclaw status and openclaw models list already own usage; the channels list code path was carrying them for no reason.
    3. "Hidden unconfigured channels": the previous implementation iterated listReadOnlyChannelPluginsForConfig(cfg) and skipped any plugin whose listAccountIds(cfg) was empty. There was no second pass over the catalog, so a channel that was installable-but-unconfigured or installed-but-unconfigured never appeared in the listing.
    4. WeCom-class regression in the first pass of --all: the --all catalog-only pass filtered with !installedByChannelId.get(entry.id), assuming "not already rendered as a plugin row → not installed". That assumption is wrong for catalog plugins whose npm package is on disk but whose config entry is absent: the read-only channel loader activates channels only if they appear in user config, so the plugin object is never surfaced, yet the manifest-based install probe reports installed: true. Both pieces were needed to drop the row.
  • Missing detection / guardrail: no unit test previously asserted that every catalog channel — installed or not — appears under --all. The auth-profiles test actively asserted the auth section was present, which is why dropping it required a rewrite of that spec. There was also no test asserting that channels list does not fetch provider usage; the command's boundary was only enforced by convention.
  • Contributing context (if known): catalog channels use pluginId ≠ channelId (e.g. WeCom catalog pluginId=wecom-openclaw-plugin, channelId=wecom), so any implementation that keys on pluginId rather than channelId is additionally prone to mismatch here. The fix keys everything on channelId, matching catalog entry id.

Regression Test Plan (if applicable)

  • Coverage level that should have caught this:
    • Unit test
    • Seam / integration test
    • End-to-end test
    • Existing coverage already sufficient
  • Target test or file: src/commands/channels.list.test.ts (new; replaces the narrower channels.list.auth-profiles.test.ts).
  • Scenario the test should lock in:
    • Auth providers are not rendered (text) or included (JSON) — both positive and negative assertions.
    • Model-provider usage is not fetched and payload.usage is undefined in JSON.
    • Default output does not surface installable or bundled-unconfigured channels.
    • --all surfaces uninstalled catalog channels with not installed, not configured, disabled.
    • --all surfaces bundled-unconfigured plugins with installed, not configured, disabled.
    • --all surfaces catalog channels installed on disk but unconfigured with installed, not configured, disabled (WeCom-class regression).
    • JSON origin correctly maps configured / available / installable across all three states.
  • Why this is the smallest reliable guardrail: channels list is a pure formatter over (cfg, read-only-plugins, catalog, installed-probe). Mocking those four seams produces deterministic output and directly covers the discovery logic the bug lived in, without requiring a live catalog fetch or a real npm install.
  • Existing test that already covers this (if any): none prior — channels.list.auth-profiles.test.ts asserted auth section presence, which was the opposite invariant.
  • If no new test is added, why not: N/A, new test added.

User-visible / Behavior Changes

  • openclaw channels list text output no longer prints the Auth providers (OAuth + API keys): block or the model-provider usage/quota snapshot. Operators who previously scanned channels list for provider auth must use openclaw models auth list; those who wanted usage must use openclaw status (overview) or openclaw models list (per-provider). The command prints one static migration line at the bottom pointing at the replacement entry points.
  • openclaw channels list --json no longer includes the auth or usage fields. Tooling that read them must migrate to openclaw models auth list --json and openclaw status --json / openclaw models list --json respectively.
  • --no-usage is gone. Running openclaw channels list --no-usage now errors with "unknown option"; there is nothing left to opt out of, and the provider usage fetch no longer happens at all on this path.
  • New --all flag on openclaw channels list. Absent it, the default output is unchanged (modulo the auth-providers / usage / --no-usage removals) and still shows only channels with a configured account.
  • New per-row status tags: installed | not installed, configured | not configured, enabled | disabled. Existing token= / bot= / app= / base= / linked bits are preserved when present.
  • New JSON per-channel shape: { accounts: string[], installed: boolean, origin: "configured" | "available" | "installable" }. Previously the value was a bare string[] of account ids.
  • Empty-state hint: when the default listing has no configured channels, output now suggests openclaw channels list --all.

Diagram (if applicable)

Before:
openclaw channels list
  ├── Chat channels:
  │     - <configured-only rows, one block of tags>     # unconfigured or uninstalled: hidden
  ├── Auth providers (OAuth + API keys):
  │     - openrouter:default (api_key)                  # model-provider leak into channels cmd
  │     - openai-codex:default (oauth)
  │     ...
  └── <Model-provider usage block>                      # per-provider billing fetch fan-out
        - anthropic:   ...
        - openrouter:  ...
        - openai-codex: ...                             # blocking; could fail with HTTP 403

After:
openclaw channels list            # unchanged default: configured accounts only
  └── Chat channels:               # no auth block, no usage block, no --no-usage flag
        - <configured>          installed, configured, enabled          [origin=configured]
  + one static line: "Model provider usage moved out of `channels list` — see `openclaw
    status` or `openclaw models list`."

openclaw channels list --all      # new: full operator-reachable surface
  └── Chat channels:
        - <configured>          installed, configured, enabled          [origin=configured]
        - <installed-unconf.>   installed, not configured, disabled     [origin=available]
        - <installable>         not installed, not configured, disabled [origin=installable]

JSON:
  Before: { "chat": { "telegram": ["default","alerts"] }, "auth": [...], "usage": {...} }
  After:  { "chat": { "telegram": { "accounts": ["default","alerts"], "installed": true,
                                    "origin": "configured" } } }       # no "auth", no "usage"

Security Impact (required)

  • New permissions/capabilities? No
  • Secrets/tokens handling changed? No (removing the auth-providers section only stops rendering provider ids that were already rendered; no secret handling changes, no new reads, no new writes)
  • New/changed network calls? Yes — strictly fewer. channels list no longer fans out to model-provider billing/auth endpoints via loadProviderUsageSummary. Every network call in the previous path is gone. openclaw status and openclaw models list still make the same calls they already made.
  • Command/tool execution surface changed? No
  • Data access scope changed? Yes — strictly narrower. channels list no longer reads loadAuthProfileStoreWithoutExternalProfiles and no longer reads provider-usage state. Catalog entries and the installed-probe it now reads were already readable by other channels subcommands.

Repro + Verification

Environment

  • OS: Linux (local dev workstation)
  • Runtime/container: Node v24.14.0, pnpm workspace, scripts/run-node.mjs dispatch
  • Model/provider: N/A (no model calls on this path)
  • Integration/channel (if any): qqbot (configured), @wecom/wecom-openclaw-plugin (installed but no config entry), plus the unmodified bundled channel set
  • Relevant config (redacted):
    {
      "channels": { "qqbot": { "accounts": { "default": {  } } } },
      "plugins":  { "entries": { "openrouter": { }, "qqbot": { } } }
    }

Steps

  1. Check out this branch and run pnpm build (or install from the published build).
  2. pnpm openclaw channels list — expect only configured QQ Bot default: installed, configured, enabled, no Auth providers block, no model-provider usage block, one static "Model provider usage moved out of channels list — see openclaw status or openclaw models list." line at the bottom.
  3. pnpm openclaw channels list --all — expect QQ Bot, WeCom (installed, not configured, disabled), and every bundled / catalog entry with correct status tags.
  4. pnpm openclaw channels list --all --json — expect chat.qqbot.origin === "configured", chat.wecom.origin === "available", chat.telegram.origin === "installable"; expect no auth key and no usage key.
  5. pnpm openclaw channels list --no-usage — expect Commander error "unknown option '--no-usage'".

Expected

  • Default path shows configured channels only (backward compatible row shape minus the dropped auth and usage blocks).
  • --all includes every catalog + bundled channel with accurate installed / configured / enabled tags, including WeCom.
  • JSON payload carries origin and installed for every rendered channel; no auth or usage fields.
  • --no-usage is rejected; the command no longer accepts it.

Actual

  • Matches expected on all five commands.

Evidence

  • Failing test/log before + passing after (rewrite of channels.list.auth-profiles.test.tschannels.list.test.ts; new WeCom regression test added; 9 passed / 9).
  • Trace/log snippets — terminal captures included under "Real behavior proof".
  • Screenshot/recording
  • Perf numbers (if relevant)

Human Verification (required)

  • Verified scenarios:
    • Ran pnpm openclaw channels list, channels list --all, and their --json counterparts against a local config that has qqbot configured and @wecom/wecom-openclaw-plugin installed but unconfigured; confirmed WeCom now appears with installed, not configured, disabled and both the auth and usage sections are gone.
    • Confirmed channels list --no-usage now errors with "unknown option" instead of silently no-op'ing.
    • Confirmed the default (non---all) output's configured-row shape is unchanged; only the blocks under it changed.
    • Confirmed --all JSON maps origin correctly across configured / available / installable and that no auth / usage keys appear.
    • Ran the new unit tests locally: 9 passed / 9 (25 ms). Ran the route-args test impacted by the new all flag and the removed --no-usage: 33 passed / 33 (40 ms).
  • Edge cases checked:
    • Operator-disabled channels (plugins.entries.<id>.enabled: false / channels.<id>.enabled: false) still render with disabled tag under --all instead of being silently dropped.
    • Catalog entries whose pluginId differs from channelId (WeCom, Weixin) resolve correctly because everything is keyed on channelId.
    • Empty default state emits a human-readable hint pointing at --all, not a blank "Chat channels:" header.
    • Provider-usage failure (network unreachable) no longer matters for channels list at all; there is no fetch on this path to fail.
  • What you did not verify:
    • Full-volume --all on deployments with dozens of installed catalog plugins (tested set was ~25 entries).
    • openclaw status and openclaw models list usage rendering — unchanged by this PR and covered by their own tests.

Review Conversations

  • I replied to or resolved every bot review conversation I addressed in this PR.
  • I left unresolved only the conversations that still need reviewer or maintainer judgment.

Compatibility / Migration

  • Backward compatible? Mostly — default text row shape for configured channels is compatible; the dropped sections (auth, usage) and the removed --no-usage flag are not.
  • Config/env changes? No
  • Migration needed? Yes, for CLI flag users and JSON consumers
  • If yes, exact upgrade steps:
    • If your tooling passed openclaw channels list --no-usage: drop the flag. The provider-usage fetch is gone, so there is nothing to skip.
    • If your tooling read openclaw channels list --json's auth field: switch to openclaw models auth list --json. Same profile set, owned by the correct command.
    • If your tooling read openclaw channels list --json's usage field: switch to openclaw status --json (overview) or openclaw models list --json (per-provider). Both already expose usage in the same provider-usage format.
    • If your tooling read openclaw channels list --json's chat.<id> as a string[]: update to consume chat.<id>.accounts (same data, new nesting). The new object also exposes installed: boolean and origin: "configured" | "available" | "installable" which you can use to filter.
    • No action needed for text output consumers that only scrape the Chat channels: block; the - <label> <accountId>: row prefix and docs-link footer are unchanged.

Risks and Mitigations

  • Risk: CLI users passing openclaw channels list --no-usage in scripts will fail with "unknown option".
    • Mitigation: migration step documented above in one line — drop the flag, the work it disabled no longer happens. The failure mode is loud (Commander rejects it) rather than silent, which is the safer direction.
  • Risk: JSON consumers that relied on the auth field, the usage field, or on chat.<id> being a string[] will break on upgrade.
    • Mitigation: each case has a one-line migration pointer above (openclaw models auth list --json / openclaw status --json / openclaw models list --json). The shape change keeps field names stable where they overlap (accounts still holds the same string list under the new object).
  • Risk: --all performs one extra isCatalogChannelInstalled check per catalog entry, which does a manifest scan. On deployments with very large catalogs this could add noticeable latency to channels list --all.
    • Mitigation: the default (channels list without --all) path is unchanged and still runs zero extra catalog work. --all is explicit operator opt-in. The extra call reuses the existing manifest snapshot helper, so there is no additional filesystem traversal beyond what openclaw onboard and openclaw channels add already perform in their steady state. Net effect on the default path is strictly less work than before, because the usage fan-out is gone.
  • Risk: operators accustomed to finding model-provider auth or usage in channels list will not immediately realize it moved.
    • Mitigation: channels list prints a single static migration pointer at the bottom of every run ("Model provider usage moved out of channels list — see openclaw status or openclaw models list."). docs/cli/channels.md was updated to spell out both migrations in the common-commands section and the troubleshooting section. Both removed sections were header blocks, so their disappearance is obvious on first run; no silent drop.

@openclaw-barnacle openclaw-barnacle Bot added docs Improvements or additions to documentation cli CLI command changes commands Command implementations size: L maintainer Maintainer-authored PR labels May 6, 2026
@clawsweeper
Copy link
Copy Markdown
Contributor

clawsweeper Bot commented May 6, 2026

Codex review: needs maintainer review before merge.

Summary
Review failed before ClawSweeper could summarize the requested change.

Reproducibility: unclear. The review failed before ClawSweeper could establish a reproduction path.

Real behavior proof
Not applicable: Real behavior proof was not assessed because the Codex review failed.

Next step before merge
Review did not complete, so no work-lane recommendation was made.

Review details

Best possible solution:

Retry the Codex review after fixing the execution failure.

Do we have a high-confidence way to reproduce the issue?

Unclear. The review failed before ClawSweeper could establish a reproduction path.

Is this the best way to solve the issue?

Unclear. Retry the review first so ClawSweeper can evaluate the actual issue and fix direction.

What I checked:

  • failure reason: timeout.
  • codex failure detail: Codex review failed for this PR: spawnSync codex ETIMEDOUT.
  • codex stdout: Per-item Codex failure; continuing with the rest of the shard.

Likely related people:

  • unknown: Codex failed before it could trace repository history. (role: review did not complete; confidence: low)

Remaining risk / open question:

  • No close action taken because the review did not complete.

Codex review notes: model gpt-5.5, reasoning high; reviewed against 1831e124b221.

@sliverp sliverp force-pushed the feat/channels-list-show-all-and-drop-auth branch from f5edc4e to 059fe3a Compare May 7, 2026 02:55
@sliverp
Copy link
Copy Markdown
Member Author

sliverp commented May 7, 2026

Behavior after the change:
openclaw channels

Clipboard_Screenshot_1778134722

openclaw channels list

Clipboard_Screenshot_1778134766

openclaw channels list -h

Clipboard_Screenshot_1778134817

openclaw channels list --all

Clipboard_Screenshot_1778134854

openclaw channels list --all --json

Clipboard_Screenshot_1778134919

@sliverp sliverp force-pushed the feat/channels-list-show-all-and-drop-auth branch from 20e219e to 09be1b4 Compare May 7, 2026 09:25
sliverp added 5 commits May 7, 2026 17:26
…d/configured/enabled

`openclaw channels list` used to conflate two very different surfaces: chat
channels and OAuth/API-key auth providers for model routing. The auth
section was the first and most visible block in the output even for
operators who only cared about chat channels, and its JSON `auth` key
leaked model-provider identities into a command whose top-level help
describes it as channel management. Worse, the command silently hid
every channel that had no configured account, so users could not tell
from `channels list` which bundled or catalog channels were even
available to configure.

Split the surface cleanly around channels only:

1. Remove the `Auth providers (OAuth + API keys)` text section and the
   `auth` field from the JSON payload. Model-provider auth profiles
   remain reachable via `openclaw models auth list`, which is where
   they conceptually belong.

2. Add a `--all` flag to surface every channel an operator could
   configure: bundled channel plugins that have no account yet and
   catalog-listed external channels whose plugin package is not even
   installed on disk. Without `--all` the output still shows only
   channels with at least one configured account, matching the
   previous default behavior so existing scripts keep working. The
   "empty" default path now prints a hint pointing at `--all`.

3. Render three explicit status tags per row — `installed` /
   `not installed`, `configured` / `not configured`, `enabled` /
   `disabled` — so bundled-but-unconfigured plugins and installable
   catalog channels both render with accurate state instead of being
   invisible. Installed state comes from the same
   `isCatalogChannelInstalled` probe the setup flow uses, so it stays
   consistent with `openclaw onboard` and `channels add`.

4. JSON payload now carries an `origin` per channel (`configured`,
   `available`, `installable`) alongside `installed: boolean`, which
   lets tooling distinguish "user has set this up" from "user could
   set this up" without second-guessing.

Register `--all` on both the Commander CLI and the fast-path route-arg
parser so the flag works in both code paths, update the one routes
test that asserted the parsed args shape, and rewrite the old auth
profiles surface test as a broader `channels list` behavior spec
covering default output, `--all` output, JSON shape (no `auth`), and
the bundled-unconfigured + catalog-not-installed cases.

Docs: call out that `channels list` is chat-channel only now, mention
`--all`, and point at `openclaw models auth list` for what used to be
the auth providers block.
…sk but not yet configured

The previous `--all` path filtered catalog entries with
`!installedByChannelId.get(entry.id)` before rendering them as
catalog-only rows. That assumed "catalog entry not already rendered
as a plugin row" implied "not installed", which is wrong: an external
channel plugin package can be installed on disk (`isCatalogChannelInstalled`
returns true) while the read-only channel loader still declines to
surface a plugin object for it — the loader only activates channels
that appear in user config, so a plugin that is installed but never
configured ended up in neither bucket and silently dropped out of
`channels list --all`.

Operator-facing symptom: `pnpm openclaw channels list --all` omitted
WeCom (and any other catalog channel in the same state) even though
its npm package was present on disk and its catalog entry existed,
while rendering every other uninstalled catalog channel as expected.

Fix: drop the `installed` filter from `catalogOnlyLines` so every
catalog entry that is not already represented by a plugin row is
rendered, and let the row itself carry the real installed/not-installed
tag. Two renderings now land in the catalog-only bucket:

- Not installed — rendered as `not installed, not configured, disabled`
  (installable row).
- Installed but unconfigured — rendered as `installed, not configured,
  disabled` (ready-to-configure row). The JSON `origin` for this case
  becomes `available`, matching the existing origin for bundled
  plugins that are installed but unconfigured, so downstream tooling
  sees a consistent "you could configure this now" signal regardless
  of whether the plugin came from bundled sources or from the catalog.

Regression test added under the WeCom scenario.
…command channel-only

`openclaw channels list` used to append a model-provider usage/quota
snapshot (Anthropic, OpenRouter, OpenAI Codex, Gemini, Zai, Minimax,
etc.) under every invocation. That was a leftover from the days when
`channels list` was the only "operator overview" command; the same
data is now owned by `openclaw status` (overview) and
`openclaw models list` (per-provider), which handle timeouts, probe
errors, and output shape consistently for that class of data. Keeping
the snapshot wired into `channels list` meant:

- Every default invocation made one blocking `loadProviderUsageSummary`
  call that fanned out to every configured provider billing/auth
  endpoint, adding seconds of latency to a command that otherwise
  just reads local config.
- `channels list --no-usage` was the escape hatch, but the flag was
  itself a self-sustaining bug: it only existed because the command
  did work that did not belong to it.
- JSON consumers had an optional `usage` key whose shape was owned by
  the provider-usage module, not by the channels module, so any
  change upstream silently reshaped `channels list --json` output.
- Failed provider fetches printed provider-side errors on a command
  that never advertised itself as a provider-health surface.

Scope this PR tightens, in one move:

1. Remove `loadProviderUsageSummary` / `formatUsageReportLines` usage
   from `src/commands/channels/list.ts`. The command now only reads
   config, the read-only channel plugin registry, and the trusted
   catalog — matching its name.
2. Drop `--no-usage` from the Commander CLI registration, from the
   fast-path route-arg parser (`parseChannelsListRouteArgs`), and
   from `ChannelsListOptions`. The flag is gone, not silently
   ignored, so anyone depending on it will get a clear
   "unknown option" from Commander and from the fast-path router.
3. Drop the `usage` key from `channels list --json` payloads. Shape
   of the `chat` record and the new `origin` / `installed` tags
   introduced earlier in this branch are unchanged.
4. Print a single-line migration pointer at the bottom of the text
   output so operators who expected usage know where it went
   (`openclaw status` / `openclaw models list`). This replaces what
   used to be a block of fetched provider data with one static line,
   so it cannot fail or add latency.
5. Update `docs/cli/channels.md` troubleshooting to remove the
   `--no-usage` mention and point at the two new entry points.
6. Update tests: drop the `loadProviderUsageSummary` mock and the
   `"keeps JSON output valid when usage loading fails"` case,
   replace it with a positive assertion that `payload.usage` is
   undefined (locking in the narrower contract), and remove `usage`
   from every `channelsListCommand(...)` call to match the narrowed
   `ChannelsListOptions` type. The route-args test is updated to
   expect `{ json, all }` without `usage`.

No other command changes. `openclaw status` and `openclaw models list`
already render usage; they are the documented replacements.

Breaking-ish surface:

- CLI: `channels list --no-usage` now fails with "unknown option".
  Tooling should drop the flag — there is nothing left to opt out of.
- JSON: `channels list --json` no longer carries a top-level `usage`
  key. Tooling that read it must migrate to
  `openclaw status --json` or `openclaw models list --json`.
…re to accept entry param

CI typecheck failed because the mock was declared with a zero-arg signature while one test called mockImplementation(({ entry }) => …). Tighten the generic so vitest's mock accepts the same params the real helper does.
@sliverp sliverp force-pushed the feat/channels-list-show-all-and-drop-auth branch from 09be1b4 to 5d7a70a Compare May 7, 2026 09:27
@sliverp sliverp merged commit 9170243 into main May 7, 2026
72 of 84 checks passed
@sliverp sliverp deleted the feat/channels-list-show-all-and-drop-auth branch May 7, 2026 09:28
@sliverp
Copy link
Copy Markdown
Member Author

sliverp commented May 7, 2026

Landed via temp rebase onto main.

  • Gate: pnpm lint && pnpm build && pnpm test
  • Land commit: 5d7a70a
  • Merge commit: 9170243

Thanks @sliverp!

steipete pushed a commit that referenced this pull request May 7, 2026
* feat(channels list): drop auth providers, add --all, surface installed/configured/enabled

`openclaw channels list` used to conflate two very different surfaces: chat
channels and OAuth/API-key auth providers for model routing. The auth
section was the first and most visible block in the output even for
operators who only cared about chat channels, and its JSON `auth` key
leaked model-provider identities into a command whose top-level help
describes it as channel management. Worse, the command silently hid
every channel that had no configured account, so users could not tell
from `channels list` which bundled or catalog channels were even
available to configure.

Split the surface cleanly around channels only:

1. Remove the `Auth providers (OAuth + API keys)` text section and the
   `auth` field from the JSON payload. Model-provider auth profiles
   remain reachable via `openclaw models auth list`, which is where
   they conceptually belong.

2. Add a `--all` flag to surface every channel an operator could
   configure: bundled channel plugins that have no account yet and
   catalog-listed external channels whose plugin package is not even
   installed on disk. Without `--all` the output still shows only
   channels with at least one configured account, matching the
   previous default behavior so existing scripts keep working. The
   "empty" default path now prints a hint pointing at `--all`.

3. Render three explicit status tags per row — `installed` /
   `not installed`, `configured` / `not configured`, `enabled` /
   `disabled` — so bundled-but-unconfigured plugins and installable
   catalog channels both render with accurate state instead of being
   invisible. Installed state comes from the same
   `isCatalogChannelInstalled` probe the setup flow uses, so it stays
   consistent with `openclaw onboard` and `channels add`.

4. JSON payload now carries an `origin` per channel (`configured`,
   `available`, `installable`) alongside `installed: boolean`, which
   lets tooling distinguish "user has set this up" from "user could
   set this up" without second-guessing.

Register `--all` on both the Commander CLI and the fast-path route-arg
parser so the flag works in both code paths, update the one routes
test that asserted the parsed args shape, and rewrite the old auth
profiles surface test as a broader `channels list` behavior spec
covering default output, `--all` output, JSON shape (no `auth`), and
the bundled-unconfigured + catalog-not-installed cases.

Docs: call out that `channels list` is chat-channel only now, mention
`--all`, and point at `openclaw models auth list` for what used to be
the auth providers block.

* fix(channels list): surface catalog channels that are installed on disk but not yet configured

The previous `--all` path filtered catalog entries with
`!installedByChannelId.get(entry.id)` before rendering them as
catalog-only rows. That assumed "catalog entry not already rendered
as a plugin row" implied "not installed", which is wrong: an external
channel plugin package can be installed on disk (`isCatalogChannelInstalled`
returns true) while the read-only channel loader still declines to
surface a plugin object for it — the loader only activates channels
that appear in user config, so a plugin that is installed but never
configured ended up in neither bucket and silently dropped out of
`channels list --all`.

Operator-facing symptom: `pnpm openclaw channels list --all` omitted
WeCom (and any other catalog channel in the same state) even though
its npm package was present on disk and its catalog entry existed,
while rendering every other uninstalled catalog channel as expected.

Fix: drop the `installed` filter from `catalogOnlyLines` so every
catalog entry that is not already represented by a plugin row is
rendered, and let the row itself carry the real installed/not-installed
tag. Two renderings now land in the catalog-only bucket:

- Not installed — rendered as `not installed, not configured, disabled`
  (installable row).
- Installed but unconfigured — rendered as `installed, not configured,
  disabled` (ready-to-configure row). The JSON `origin` for this case
  becomes `available`, matching the existing origin for bundled
  plugins that are installed but unconfigured, so downstream tooling
  sees a consistent "you could configure this now" signal regardless
  of whether the plugin came from bundled sources or from the catalog.

Regression test added under the WeCom scenario.

* refactor(channels list): drop model-provider usage surface, make the command channel-only

`openclaw channels list` used to append a model-provider usage/quota
snapshot (Anthropic, OpenRouter, OpenAI Codex, Gemini, Zai, Minimax,
etc.) under every invocation. That was a leftover from the days when
`channels list` was the only "operator overview" command; the same
data is now owned by `openclaw status` (overview) and
`openclaw models list` (per-provider), which handle timeouts, probe
errors, and output shape consistently for that class of data. Keeping
the snapshot wired into `channels list` meant:

- Every default invocation made one blocking `loadProviderUsageSummary`
  call that fanned out to every configured provider billing/auth
  endpoint, adding seconds of latency to a command that otherwise
  just reads local config.
- `channels list --no-usage` was the escape hatch, but the flag was
  itself a self-sustaining bug: it only existed because the command
  did work that did not belong to it.
- JSON consumers had an optional `usage` key whose shape was owned by
  the provider-usage module, not by the channels module, so any
  change upstream silently reshaped `channels list --json` output.
- Failed provider fetches printed provider-side errors on a command
  that never advertised itself as a provider-health surface.

Scope this PR tightens, in one move:

1. Remove `loadProviderUsageSummary` / `formatUsageReportLines` usage
   from `src/commands/channels/list.ts`. The command now only reads
   config, the read-only channel plugin registry, and the trusted
   catalog — matching its name.
2. Drop `--no-usage` from the Commander CLI registration, from the
   fast-path route-arg parser (`parseChannelsListRouteArgs`), and
   from `ChannelsListOptions`. The flag is gone, not silently
   ignored, so anyone depending on it will get a clear
   "unknown option" from Commander and from the fast-path router.
3. Drop the `usage` key from `channels list --json` payloads. Shape
   of the `chat` record and the new `origin` / `installed` tags
   introduced earlier in this branch are unchanged.
4. Print a single-line migration pointer at the bottom of the text
   output so operators who expected usage know where it went
   (`openclaw status` / `openclaw models list`). This replaces what
   used to be a block of fetched provider data with one static line,
   so it cannot fail or add latency.
5. Update `docs/cli/channels.md` troubleshooting to remove the
   `--no-usage` mention and point at the two new entry points.
6. Update tests: drop the `loadProviderUsageSummary` mock and the
   `"keeps JSON output valid when usage loading fails"` case,
   replace it with a positive assertion that `payload.usage` is
   undefined (locking in the narrower contract), and remove `usage`
   from every `channelsListCommand(...)` call to match the narrowed
   `ChannelsListOptions` type. The route-args test is updated to
   expect `{ json, all }` without `usage`.

No other command changes. `openclaw status` and `openclaw models list`
already render usage; they are the documented replacements.

Breaking-ish surface:

- CLI: `channels list --no-usage` now fails with "unknown option".
  Tooling should drop the flag — there is nothing left to opt out of.
- JSON: `channels list --json` no longer carries a top-level `usage`
  key. Tooling that read it must migrate to
  `openclaw status --json` or `openclaw models list --json`.

* fix(channels.list.test): widen isCatalogChannelInstalled mock signature to accept entry param

CI typecheck failed because the mock was declared with a zero-arg signature while one test called mockImplementation(({ entry }) => …). Tighten the generic so vitest's mock accepts the same params the real helper does.

* changelog: record channels list channel-only rework (#78456)
github-actions Bot pushed a commit to Desicool/openclaw that referenced this pull request May 9, 2026
* feat(channels list): drop auth providers, add --all, surface installed/configured/enabled

`openclaw channels list` used to conflate two very different surfaces: chat
channels and OAuth/API-key auth providers for model routing. The auth
section was the first and most visible block in the output even for
operators who only cared about chat channels, and its JSON `auth` key
leaked model-provider identities into a command whose top-level help
describes it as channel management. Worse, the command silently hid
every channel that had no configured account, so users could not tell
from `channels list` which bundled or catalog channels were even
available to configure.

Split the surface cleanly around channels only:

1. Remove the `Auth providers (OAuth + API keys)` text section and the
   `auth` field from the JSON payload. Model-provider auth profiles
   remain reachable via `openclaw models auth list`, which is where
   they conceptually belong.

2. Add a `--all` flag to surface every channel an operator could
   configure: bundled channel plugins that have no account yet and
   catalog-listed external channels whose plugin package is not even
   installed on disk. Without `--all` the output still shows only
   channels with at least one configured account, matching the
   previous default behavior so existing scripts keep working. The
   "empty" default path now prints a hint pointing at `--all`.

3. Render three explicit status tags per row — `installed` /
   `not installed`, `configured` / `not configured`, `enabled` /
   `disabled` — so bundled-but-unconfigured plugins and installable
   catalog channels both render with accurate state instead of being
   invisible. Installed state comes from the same
   `isCatalogChannelInstalled` probe the setup flow uses, so it stays
   consistent with `openclaw onboard` and `channels add`.

4. JSON payload now carries an `origin` per channel (`configured`,
   `available`, `installable`) alongside `installed: boolean`, which
   lets tooling distinguish "user has set this up" from "user could
   set this up" without second-guessing.

Register `--all` on both the Commander CLI and the fast-path route-arg
parser so the flag works in both code paths, update the one routes
test that asserted the parsed args shape, and rewrite the old auth
profiles surface test as a broader `channels list` behavior spec
covering default output, `--all` output, JSON shape (no `auth`), and
the bundled-unconfigured + catalog-not-installed cases.

Docs: call out that `channels list` is chat-channel only now, mention
`--all`, and point at `openclaw models auth list` for what used to be
the auth providers block.

* fix(channels list): surface catalog channels that are installed on disk but not yet configured

The previous `--all` path filtered catalog entries with
`!installedByChannelId.get(entry.id)` before rendering them as
catalog-only rows. That assumed "catalog entry not already rendered
as a plugin row" implied "not installed", which is wrong: an external
channel plugin package can be installed on disk (`isCatalogChannelInstalled`
returns true) while the read-only channel loader still declines to
surface a plugin object for it — the loader only activates channels
that appear in user config, so a plugin that is installed but never
configured ended up in neither bucket and silently dropped out of
`channels list --all`.

Operator-facing symptom: `pnpm openclaw channels list --all` omitted
WeCom (and any other catalog channel in the same state) even though
its npm package was present on disk and its catalog entry existed,
while rendering every other uninstalled catalog channel as expected.

Fix: drop the `installed` filter from `catalogOnlyLines` so every
catalog entry that is not already represented by a plugin row is
rendered, and let the row itself carry the real installed/not-installed
tag. Two renderings now land in the catalog-only bucket:

- Not installed — rendered as `not installed, not configured, disabled`
  (installable row).
- Installed but unconfigured — rendered as `installed, not configured,
  disabled` (ready-to-configure row). The JSON `origin` for this case
  becomes `available`, matching the existing origin for bundled
  plugins that are installed but unconfigured, so downstream tooling
  sees a consistent "you could configure this now" signal regardless
  of whether the plugin came from bundled sources or from the catalog.

Regression test added under the WeCom scenario.

* refactor(channels list): drop model-provider usage surface, make the command channel-only

`openclaw channels list` used to append a model-provider usage/quota
snapshot (Anthropic, OpenRouter, OpenAI Codex, Gemini, Zai, Minimax,
etc.) under every invocation. That was a leftover from the days when
`channels list` was the only "operator overview" command; the same
data is now owned by `openclaw status` (overview) and
`openclaw models list` (per-provider), which handle timeouts, probe
errors, and output shape consistently for that class of data. Keeping
the snapshot wired into `channels list` meant:

- Every default invocation made one blocking `loadProviderUsageSummary`
  call that fanned out to every configured provider billing/auth
  endpoint, adding seconds of latency to a command that otherwise
  just reads local config.
- `channels list --no-usage` was the escape hatch, but the flag was
  itself a self-sustaining bug: it only existed because the command
  did work that did not belong to it.
- JSON consumers had an optional `usage` key whose shape was owned by
  the provider-usage module, not by the channels module, so any
  change upstream silently reshaped `channels list --json` output.
- Failed provider fetches printed provider-side errors on a command
  that never advertised itself as a provider-health surface.

Scope this PR tightens, in one move:

1. Remove `loadProviderUsageSummary` / `formatUsageReportLines` usage
   from `src/commands/channels/list.ts`. The command now only reads
   config, the read-only channel plugin registry, and the trusted
   catalog — matching its name.
2. Drop `--no-usage` from the Commander CLI registration, from the
   fast-path route-arg parser (`parseChannelsListRouteArgs`), and
   from `ChannelsListOptions`. The flag is gone, not silently
   ignored, so anyone depending on it will get a clear
   "unknown option" from Commander and from the fast-path router.
3. Drop the `usage` key from `channels list --json` payloads. Shape
   of the `chat` record and the new `origin` / `installed` tags
   introduced earlier in this branch are unchanged.
4. Print a single-line migration pointer at the bottom of the text
   output so operators who expected usage know where it went
   (`openclaw status` / `openclaw models list`). This replaces what
   used to be a block of fetched provider data with one static line,
   so it cannot fail or add latency.
5. Update `docs/cli/channels.md` troubleshooting to remove the
   `--no-usage` mention and point at the two new entry points.
6. Update tests: drop the `loadProviderUsageSummary` mock and the
   `"keeps JSON output valid when usage loading fails"` case,
   replace it with a positive assertion that `payload.usage` is
   undefined (locking in the narrower contract), and remove `usage`
   from every `channelsListCommand(...)` call to match the narrowed
   `ChannelsListOptions` type. The route-args test is updated to
   expect `{ json, all }` without `usage`.

No other command changes. `openclaw status` and `openclaw models list`
already render usage; they are the documented replacements.

Breaking-ish surface:

- CLI: `channels list --no-usage` now fails with "unknown option".
  Tooling should drop the flag — there is nothing left to opt out of.
- JSON: `channels list --json` no longer carries a top-level `usage`
  key. Tooling that read it must migrate to
  `openclaw status --json` or `openclaw models list --json`.

* fix(channels.list.test): widen isCatalogChannelInstalled mock signature to accept entry param

CI typecheck failed because the mock was declared with a zero-arg signature while one test called mockImplementation(({ entry }) => …). Tighten the generic so vitest's mock accepts the same params the real helper does.

* changelog: record channels list channel-only rework (openclaw#78456)
rogerdigital pushed a commit to rogerdigital/openclaw that referenced this pull request May 9, 2026
* feat(channels list): drop auth providers, add --all, surface installed/configured/enabled

`openclaw channels list` used to conflate two very different surfaces: chat
channels and OAuth/API-key auth providers for model routing. The auth
section was the first and most visible block in the output even for
operators who only cared about chat channels, and its JSON `auth` key
leaked model-provider identities into a command whose top-level help
describes it as channel management. Worse, the command silently hid
every channel that had no configured account, so users could not tell
from `channels list` which bundled or catalog channels were even
available to configure.

Split the surface cleanly around channels only:

1. Remove the `Auth providers (OAuth + API keys)` text section and the
   `auth` field from the JSON payload. Model-provider auth profiles
   remain reachable via `openclaw models auth list`, which is where
   they conceptually belong.

2. Add a `--all` flag to surface every channel an operator could
   configure: bundled channel plugins that have no account yet and
   catalog-listed external channels whose plugin package is not even
   installed on disk. Without `--all` the output still shows only
   channels with at least one configured account, matching the
   previous default behavior so existing scripts keep working. The
   "empty" default path now prints a hint pointing at `--all`.

3. Render three explicit status tags per row — `installed` /
   `not installed`, `configured` / `not configured`, `enabled` /
   `disabled` — so bundled-but-unconfigured plugins and installable
   catalog channels both render with accurate state instead of being
   invisible. Installed state comes from the same
   `isCatalogChannelInstalled` probe the setup flow uses, so it stays
   consistent with `openclaw onboard` and `channels add`.

4. JSON payload now carries an `origin` per channel (`configured`,
   `available`, `installable`) alongside `installed: boolean`, which
   lets tooling distinguish "user has set this up" from "user could
   set this up" without second-guessing.

Register `--all` on both the Commander CLI and the fast-path route-arg
parser so the flag works in both code paths, update the one routes
test that asserted the parsed args shape, and rewrite the old auth
profiles surface test as a broader `channels list` behavior spec
covering default output, `--all` output, JSON shape (no `auth`), and
the bundled-unconfigured + catalog-not-installed cases.

Docs: call out that `channels list` is chat-channel only now, mention
`--all`, and point at `openclaw models auth list` for what used to be
the auth providers block.

* fix(channels list): surface catalog channels that are installed on disk but not yet configured

The previous `--all` path filtered catalog entries with
`!installedByChannelId.get(entry.id)` before rendering them as
catalog-only rows. That assumed "catalog entry not already rendered
as a plugin row" implied "not installed", which is wrong: an external
channel plugin package can be installed on disk (`isCatalogChannelInstalled`
returns true) while the read-only channel loader still declines to
surface a plugin object for it — the loader only activates channels
that appear in user config, so a plugin that is installed but never
configured ended up in neither bucket and silently dropped out of
`channels list --all`.

Operator-facing symptom: `pnpm openclaw channels list --all` omitted
WeCom (and any other catalog channel in the same state) even though
its npm package was present on disk and its catalog entry existed,
while rendering every other uninstalled catalog channel as expected.

Fix: drop the `installed` filter from `catalogOnlyLines` so every
catalog entry that is not already represented by a plugin row is
rendered, and let the row itself carry the real installed/not-installed
tag. Two renderings now land in the catalog-only bucket:

- Not installed — rendered as `not installed, not configured, disabled`
  (installable row).
- Installed but unconfigured — rendered as `installed, not configured,
  disabled` (ready-to-configure row). The JSON `origin` for this case
  becomes `available`, matching the existing origin for bundled
  plugins that are installed but unconfigured, so downstream tooling
  sees a consistent "you could configure this now" signal regardless
  of whether the plugin came from bundled sources or from the catalog.

Regression test added under the WeCom scenario.

* refactor(channels list): drop model-provider usage surface, make the command channel-only

`openclaw channels list` used to append a model-provider usage/quota
snapshot (Anthropic, OpenRouter, OpenAI Codex, Gemini, Zai, Minimax,
etc.) under every invocation. That was a leftover from the days when
`channels list` was the only "operator overview" command; the same
data is now owned by `openclaw status` (overview) and
`openclaw models list` (per-provider), which handle timeouts, probe
errors, and output shape consistently for that class of data. Keeping
the snapshot wired into `channels list` meant:

- Every default invocation made one blocking `loadProviderUsageSummary`
  call that fanned out to every configured provider billing/auth
  endpoint, adding seconds of latency to a command that otherwise
  just reads local config.
- `channels list --no-usage` was the escape hatch, but the flag was
  itself a self-sustaining bug: it only existed because the command
  did work that did not belong to it.
- JSON consumers had an optional `usage` key whose shape was owned by
  the provider-usage module, not by the channels module, so any
  change upstream silently reshaped `channels list --json` output.
- Failed provider fetches printed provider-side errors on a command
  that never advertised itself as a provider-health surface.

Scope this PR tightens, in one move:

1. Remove `loadProviderUsageSummary` / `formatUsageReportLines` usage
   from `src/commands/channels/list.ts`. The command now only reads
   config, the read-only channel plugin registry, and the trusted
   catalog — matching its name.
2. Drop `--no-usage` from the Commander CLI registration, from the
   fast-path route-arg parser (`parseChannelsListRouteArgs`), and
   from `ChannelsListOptions`. The flag is gone, not silently
   ignored, so anyone depending on it will get a clear
   "unknown option" from Commander and from the fast-path router.
3. Drop the `usage` key from `channels list --json` payloads. Shape
   of the `chat` record and the new `origin` / `installed` tags
   introduced earlier in this branch are unchanged.
4. Print a single-line migration pointer at the bottom of the text
   output so operators who expected usage know where it went
   (`openclaw status` / `openclaw models list`). This replaces what
   used to be a block of fetched provider data with one static line,
   so it cannot fail or add latency.
5. Update `docs/cli/channels.md` troubleshooting to remove the
   `--no-usage` mention and point at the two new entry points.
6. Update tests: drop the `loadProviderUsageSummary` mock and the
   `"keeps JSON output valid when usage loading fails"` case,
   replace it with a positive assertion that `payload.usage` is
   undefined (locking in the narrower contract), and remove `usage`
   from every `channelsListCommand(...)` call to match the narrowed
   `ChannelsListOptions` type. The route-args test is updated to
   expect `{ json, all }` without `usage`.

No other command changes. `openclaw status` and `openclaw models list`
already render usage; they are the documented replacements.

Breaking-ish surface:

- CLI: `channels list --no-usage` now fails with "unknown option".
  Tooling should drop the flag — there is nothing left to opt out of.
- JSON: `channels list --json` no longer carries a top-level `usage`
  key. Tooling that read it must migrate to
  `openclaw status --json` or `openclaw models list --json`.

* fix(channels.list.test): widen isCatalogChannelInstalled mock signature to accept entry param

CI typecheck failed because the mock was declared with a zero-arg signature while one test called mockImplementation(({ entry }) => …). Tighten the generic so vitest's mock accepts the same params the real helper does.

* changelog: record channels list channel-only rework (openclaw#78456)
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

cli CLI command changes commands Command implementations docs Improvements or additions to documentation maintainer Maintainer-authored PR size: L

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant