Commit Graph

3625 Commits

Author SHA1 Message Date
DaigoSoup
025cecf1f9 fix: avoid false macOS gateway restart failures (#109955)
* fix: wait through launchd KeepAlive restart throttling

* ci: retrigger checks

* test: make update restart test platform-independent

---------

Co-authored-by: Josh Lehman <josh@martian.engineering>
2026-07-17 17:19:23 -07:00
xingzhou
c6d4559811 fix(mcp): doctor probes no longer start every server at once (#109870)
* fix(mcp): bound doctor server checks

* fix(mcp): defer doctor concurrency helper loading

* fix(mcp): preserve doctor check coverage

---------

Co-authored-by: Peter Steinberger <steipete@gmail.com>
2026-07-18 00:59:10 +01:00
Vito Cappello
748fc04419 fix(update): classify unreadable plugin manifests (#110200)
Co-authored-by: VACInc <3279061+VACInc@users.noreply.github.com>
2026-07-17 16:33:04 -07:00
Peter Steinberger
9a93a52a8a feat(onboard): recommendations store with once-semantics and self-naming bootstrap (#110173)
* feat(onboarding): persist app recommendations once

* feat(onboarding): add self-naming birth sequence

* chore(wizard): hoist bootstrap-defer imports to the top of the module

* docs(bootstrap): persist agreed identity into IDENTITY.md and SOUL.md as well

* docs: regenerate docs map after onboarding plan merge

* fix(wizard): reuse a pending stored offer instead of rescanning apps

* fix(onboard): deduplicate bootstrap recommendations
2026-07-17 23:42:01 +01:00
Peter Steinberger
282879b394 fix(cli): write --json payloads to stdout not stderr (#109808)
node identity, promos list, daemon restart, and tasks show emitted their --json result via runtime.log() (console.log), which --json mode redirects to stderr — leaving stdout empty and breaking pipes like `openclaw node identity --json | jq`. Use writeRuntimeJson to write the payload to stdout, matching health/tasks-list/capability. Human output unchanged.
2026-07-17 21:59:30 +01:00
Peter Steinberger
62f9c247ab fix(cli): config file resolves path without initializing state (#109811)
`config file` (print the active config path) called readConfigFileSnapshot(), eagerly creating the state dir + state/openclaw.sqlite — so a --profile typo minted a stray profile tree. Resolve the path via resolveConfigPath() instead; no state initialized.
2026-07-17 21:59:16 +01:00
Peter Steinberger
198e3b37b2 feat(onboard): browser-first guided handoff (#110054)
* feat(onboard): add browser-first guided handoff

* chore: drop release-only CHANGELOG edit from browser-handoff branch

* fix(onboard): make browser handoff reach the gateway on real installs

The presence probe connected as a raw shared-auth client with a possibly
SecretRef-managed token, which the gateway rejects as an unpaired Control UI
client ("device identity required"), so the handoff never fired and always
fell through to the terminal hatch. Read presence as a CLI-mode loopback client
(the trusted path every openclaw command uses) so operator.read is granted, and
share that one auth path between the reachability gate and the wait loop. Also
short-circuit when gateway.controlUi.enabled is false so onboarding does not open
a dead dashboard URL and block for the full timeout.

* fix(onboard): share resolved target between handoff gate and wait

The reachability preflight now resolves the same target (and shared secret) the
wait loop uses, and presents the configured secret to the CLI-mode presence
read. Known remaining limitation: on fresh quickstart gateways whose auth token
is written to config but resolved differently at runtime, the presence read is
rejected with a token mismatch and the handoff falls back to the terminal hatch.
Tracked for follow-up before enabling the browser handoff by default.

* docs(onboarding): mark phase 3 browser handoff as held with diagnosis

* docs(onboarding): phase 3 proven end-to-end; token-mismatch hold was a test artifact

* fix(onboard): satisfy docs-map and test-type gates for the handoff branch

* refactor(onboard): split guided manual stage
2026-07-17 18:57:57 +01:00
Peter Steinberger
5366b6de81 refactor: store gateway restart recovery in SQLite (#110014)
* refactor: move restart sentinel state to sqlite

* fix: satisfy restart sentinel architecture gates

* test: avoid cold startup migration timeout

* fix: bound durable restart notice retries

* test: type restart notice contention mock

* fix: detect legacy restart sentinel before reads

* fix: keep delivery attempt result internal

* fix: narrow restart sentinel preflight guard
2026-07-17 17:43:22 +01:00
Peter Steinberger
da69daeb72 feat(onboarding): recommend plugins and skills from installed apps (#109668)
* feat(onboarding): recommend plugins and skills from installed apps

Scan installed macOS apps during classic onboarding (TCC-free), gather
candidates from official catalogs + ClawHub search, let the configured
model pick genuine matches, and offer an opt-in multiselect install step.
Adds a device.apps node-host command (default-off sharing, Android-parity
envelope) so remote gateways can request a paired Mac's inventory, and a
wizard.appRecommendations kill switch. Custom setup-inference completions
no longer inherit the 32-token verification-probe output cap.

* feat(onboarding): recommend apps in guided flow

* fix(onboarding): harden app recommendations against ClawHub self-promotion

Third-party ClawHub skills are never pre-selected regardless of model tier
(publisher-controlled listing text reaches the matcher prompt and could
promote itself); their labels now say they install third-party code.
Installed-app scans follow symlinked .app bundles. Matcher output stays
bounded by the resolved model's own maxTokens budget (documented invariant).

* fix(onboarding): key official catalog candidates by resolved plugin id

Real catalog entries are package manifests without a top-level id; keying the
candidate map and channel/provider classification by entry.id collapsed the
whole official catalog into one undefined-keyed entry, so no official plugin
or channel was ever recommended. Regression test runs against the bundled
catalogs.

* fix(onboarding): satisfy lint, types, deadcode, and migration gates

Split the guided-onboarding test into a self-contained custodian suite to stay
under max-lines. Narrow app-recommendation exports (drop dead node-payload
normalizer, unexport internal types/helpers, route candidate tests through the
public API), replace map-spread with a helper, unexport device.apps result
types, add installedAppsSharing to node-host migration expectations, cast the
wizard multiselect mock, and regenerate the docs map.

* test(onboarding): register new live test in the shard classifier
2026-07-17 14:07:59 +01:00
Peter Steinberger
f3d1f02dc1 refactor: move MCP OAuth state to SQLite (#109844)
* refactor(mcp): move OAuth state to SQLite

* refactor(mcp): tighten OAuth module boundaries

* chore: refresh PR merge ref

* fix(mcp): align storage docs and merge checks

* fix(mcp): surface OAuth reauthorization status
2026-07-17 12:15:16 +01:00
Peter Steinberger
66aa2eda9d fix(cli): report malformed plugin JSON paths (#109916)
* fix(cli): report malformed plugin JSON paths

Co-authored-by: 丁宇婷0668001435 <ding.yuting@xydigit.com>

* test(google-meet): keep CLI test on plugin boundary

---------

Co-authored-by: 丁宇婷0668001435 <ding.yuting@xydigit.com>
2026-07-17 11:53:23 +01:00
wuqxuan
d7056abbc8 fix(cli): reject missing separator after config path brackets (#109580)
* fix(cli): reject missing separator after config path brackets

* fix(cli): simplify bracket path separator validation

---------

Co-authored-by: Peter Steinberger <steipete@gmail.com>
2026-07-17 11:42:58 +01:00
krissding
af469c85cf fix(cli): guard secrets plan JSON.parse against malformed input (#109721)
* fix(cli): guard secrets plan JSON.parse against malformed input

readPlanFile reads a user-specified file and parses it with JSON.parse
without a try-catch. A malformed or corrupted plan file produces a raw
SyntaxError that is not user-actionable.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>

* test: tighten malformed secrets plan proof

Co-authored-by: 丁宇婷0668001435 <ding.yuting@xydigit.com>

---------

Co-authored-by: Claude Sonnet 4.6 <noreply@anthropic.com>
Co-authored-by: Peter Steinberger <steipete@gmail.com>
2026-07-17 10:00:35 +01:00
Peter Steinberger
0097363c69 fix(secrets): keep gateway alive when web provider refs fail (#109687)
* fix(secrets): isolate unavailable web providers

* fix(secrets): keep web result type internal

* fix(secrets): hide unavailable web selections
2026-07-16 23:48:37 -07:00
Peter Steinberger
9b80f9a8b1 fix(cli): emit resolved config paths in machine output, not abbreviated home (#109361)
`config file`, `config patch --dry-run --json`, and `config unset --json` ran
the config path through shortenHomePath, emitting `~/…` or the literal
`$OPENCLAW_HOME/…` token in machine output — breaking `cat $(openclaw config
file)` and corrupting JSON path fields. `agents list --json` already resolves.
Emit the raw resolved snapshot path at these machine-output sites; human table
rendering keeps the friendly abbreviation.
2026-07-16 21:45:04 -07:00
ooiuuii
7641aa80c2 fix: plugins update rewrites config for install-record-only updates (#98422)
* Avoid config rewrites for plugin index updates

* Preserve config freshness for records-only plugin updates

* Validate records-only plugin update config

* fix(plugins): reload index-only updates

Co-authored-by: luyifan <al3060388206@gmail.com>

* chore(protocol): refresh generated clients

Co-authored-by: luyifan <al3060388206@gmail.com>

* fix(gateway): wire plugin refresh handler

---------

Co-authored-by: Peter Steinberger <steipete@gmail.com>
2026-07-16 21:38:45 -07:00
Erick Kinnee
135aa7a002 fix(config): improve validation error messages with line numbers, bracket paths, and received values (#106526)
* fix(config): improve validation error messages with line numbers, bracket paths, and received values

- Add JSON5-aware path navigator (issue-location.ts) that resolves line
  numbers and received values from raw config text without a full parser
- Add formatConfigIssuePath() for bracket notation (agents.list[3])
- Add appendReceivedValueHint() for safe value display (got: "none")
- Add attachConfigIssueDiagnostics() to enrich issues with location info
- Wire enrichment into runConfigValidate() and loadValidConfig() in config-cli.ts
- Add resolveIssueLocationPrefix() to issue-format.ts for sourceFile:line prefix
- Sensitive paths and secret refs are never leaked in received value hints
- Paths in 'd files gracefully degrade (no line number shown)

Closes #104854

* fix(config): type fixes from tsgo:core validation

- Add sourceFile to ConfigIssueFormatOptions (used in resolveIssueLocationPrefix)
- Fix readKey regex test for undefined raw[c.pos]

* fix(config): satisfy eslint(curly) and formatting for issue-location.ts

- Add braces to all single-line if/while/for statements
- Run oxfmt for consistent formatting

* fix(config): trim issue-location.ts to 500 lines for LOC ratchet

* fix(config): fix formatConfigIssuePath ternary bug from trimming

* fix(config): trim issue-location.ts to 469 lines for LOC ratchet

* fix(config): format issue-location.test.ts

* fix(config): document JSON5 subset and add 20 edge case tests

- Add explicit supported-subset documentation to issue-location.ts header
- Add 20 tests covering hex numbers, leading decimals, Infinity, NaN,
  null/bool, trailing commas, deep nesting, unicode escapes, multi-line
  strings, unicode keys, escaped quotes, numeric separators, block comments,
  mixed quotes, empty objects/arrays, and graceful degradation

* fix(config): address autoreview findings on JSON5 docs and tests

- Remove numeric separator claim (not valid JSON5)
- Remove 'None known' unsupported-syntax claim, document known limitations
- Restructure scalar tests to exercise skipVal (resolve sibling after exotic value)
- Remove numeric separator test

* fix(config): constrain received value diagnostics

* fix(config): preserve JSON5 diagnostic locations

* fix(config): preserve validation path ownership

* fix(config): redact dotted plugin paths

* test(config): avoid diagnostic fixture shadowing

* refactor(config): privatize diagnostic helpers

---------

Co-authored-by: Erick Kinnee <erick@ekinnee.dev>
Co-authored-by: Peter Steinberger <steipete@gmail.com>
2026-07-16 21:01:30 -07:00
OfflynAI
def7dd2401 fix(channels): restart gateway when channels.start fails for unloaded plugin (#90779)
* fix(channels): restart gateway when channels.start fails for unloaded plugin

After channels login, the CLI calls channels.start to reconcile the running
gateway. If the channel plugin was installed or enabled after the gateway
started, the plugin is not in the runtime registry and channels.start rejects
with 'invalid channels.start channel'. Detect this error and fall back to
gateway.restart.request so the gateway reloads plugins and starts the channel
automatically.

Fixes #90296

* ci: retrigger checks (update proof section format)

Co-authored-by: Cursor <cursoragent@cursor.com>

* ci: retrigger proof check (real behavior evidence)

Co-authored-by: Cursor <cursoragent@cursor.com>

* fix(channels): narrow unloaded-plugin restart

---------

Co-authored-by: Cursor <cursoragent@cursor.com>
Co-authored-by: Peter Steinberger <steipete@gmail.com>
2026-07-16 20:21:06 -07:00
xydt-tanshanshan
a3e526a9d0 fix(daemon): prevent gateway OOM crash loops under sustained load (#96250)
* [AI] fix(daemon): set default --max-old-space-size=8192 in gateway service env

Generate a managed NODE_OPTIONS with --max-old-space-size=8192 for the
gateway systemd service, discarding ambient host NODE_OPTIONS to prevent
--require/--inspect persistence.  8192 MB is chosen as a safe default
that prevents the common OOM crash-loop with the default Node ~4 GB heap
under sustained load.

Related to #96203

* fix(daemon): adapt gateway heap limit to host memory

* fix(daemon): keep gateway heap helpers internal

---------

Co-authored-by: Peter Steinberger <steipete@gmail.com>
2026-07-16 20:12:12 -07:00
ooiuuii
a82c72904a fix: block no-auth managed gateway LAN installs (#98022)
* fix: block no-auth managed gateway LAN installs

* test(gateway): cover managed install bind resolution

Co-authored-by: luyifan <al3060388206@gmail.com>

* test(gateway): drop unrelated env cleanup

* test(gateway): use synthetic token fixture

* fix(gateway): reject dynamic tailnet no-auth installs

Co-authored-by: luyifan <al3060388206@gmail.com>

---------

Co-authored-by: Peter Steinberger <steipete@gmail.com>
2026-07-16 18:45:05 -07:00
mushuiyu886
9ff25ca65f fix(fleet): reject hexadecimal CPU limits (#105158)
Co-authored-by: Peter Steinberger <steipete@gmail.com>
2026-07-16 18:30:43 -07:00
qingminlong
d6a561e92b fix(gateway): clarify malformed call params errors (#105217)
Co-authored-by: Peter Steinberger <steipete@gmail.com>
2026-07-16 18:24:08 -07:00
Peter Steinberger
dbf3597f9b fix(cli): restore lint after restart health growth (#109359)
* fix(cli): split restart-health over max-lines

* fix(cli): drop dead export from restart-health test helpers
2026-07-16 17:13:58 -07:00
mushuiyu886
91df2d1812 fix(cli): bound container runtime probes (#109199)
Co-authored-by: Peter Steinberger <steipete@gmail.com>
Co-authored-by: Peter Steinberger <peter@steipete.me>
2026-07-16 16:54:23 -07:00
Shakker
e6c8f82f50 feat: expose ClickClack setup codes in channels add 2026-07-16 23:56:29 +01:00
krissding
ff1687e04f fix(cli): filter Commander value placeholders from Fish completion flags (#109324)
* fix(cli): filter Commander value placeholders from Fish completion flags

The Fish completion generator was treating Commander.js value placeholders
(like <path|->, <file>, [optional]) as command-line tokens, causing the
angle-bracket values to be interpreted as shell redirects when the
completion script was sourced.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>

* fix(cli): use parsed option flags for completions

Co-authored-by: 丁宇婷0668001435 <ding.yuting@xydigit.com>

* fix(cli): support long option aliases in Fish completion

Co-authored-by: 丁宇婷0668001435 <ding.yuting@xydigit.com>

---------

Co-authored-by: Claude Sonnet 4.6 <noreply@anthropic.com>
Co-authored-by: Peter Steinberger <steipete@gmail.com>
Co-authored-by: Peter Steinberger <peter@steipete.me>
2026-07-16 14:57:23 -07:00
Dallin Romney
5a0fcc2ff9 test(cli): distinguish silent hook relay completion (#109339) 2026-07-16 13:59:34 -07:00
tzy-17
543b60092d fix(cli): use startsWith for loopback IPv4 check in container proxy (#106077)
isLoopbackProxyHostname used split(".", 1)[0] === "127" to detect
127.0.0.0/8 addresses. While isIP() already rejects leading-zero octets
before this branch is reached, startsWith("127.") is more direct and
clearly expresses the intent of matching the entire 127.0.0.0/8 range.
2026-07-16 13:40:18 -07:00
thomas.szbay
b06fe2a673 fix(kill-tree): verify process group leader before using group kill to prevent gateway SIGTERM (#76259) (#94697)
* fix(kill-tree): verify process group leader before group kill to prevent gateway SIGTERM (#76259)

- Add isProcessGroupLeader() to killProcessTree/signalProcessTree: ps -p <pid> -o pgid= primary check with /proc/<pid>/stat fallback on Linux. Group kill only when the PID is its own process group leader; non-leaders fall back to single-pid kill, preventing accidental gateway SIGTERM when a non-detached child shares the gateway's process group.
- Propagate detached: true to all detached-spawn cleanup callers (exec-termination, agent-bundle LSP, mcp-stdio, bash, supervisor pty, agent-core nodejs) so detached group cleanup survives leader exit.
- Gateway/daemon cleanup paths (schtasks, restart-health) keep the leader-checked default (detached omitted).

Closes #76259

Co-Authored-By: Claude <noreply@anthropic.com>

* refactor(process): tighten process-group ownership checks

* refactor(daemon): split restart diagnostics

* refactor(daemon): isolate restart health types

---------

Co-authored-by: Claude <noreply@anthropic.com>
Co-authored-by: Peter Steinberger <steipete@gmail.com>
2026-07-16 12:30:51 -07:00
Peter Steinberger
734e1ed369 refactor(daemon): split restart port ownership helpers (#109298) 2026-07-16 12:15:48 -07:00
Peter Steinberger
6c39e713d4 refactor: move native hook relay registry to SQLite (#109289)
* refactor: store native hook relays in SQLite

* chore: satisfy relay store CI checks
2026-07-16 12:14:06 -07:00
Shakker
f084ab2240 fix: prevent external gateway restart timeouts (#109273) 2026-07-16 19:36:58 +01:00
Peter Steinberger
f871b499b6 fix(infra): drop consumer-less gateway supervision exports
333c4f9a61 and 244f4965dc landed six exports with no production
consumers, failing the hard-zero deadcode gate on every PR: a dead
re-export block in restart-handoff (the contract module's real importer
uses it directly), three result/mode types only referenced inside their
own modules, and two supervision symbols whose only consumers were their
tests. The types and helpers stay defined for the in-flight supervisor
work to re-export alongside real consumers; the supervision test now
proves mode resolution through the public isGatewayExternallySupervised
surface.
2026-07-16 09:31:46 -07:00
Shakker
9b48ad5977 fix: avoid redundant Windows restart persistence (#109162) 2026-07-16 17:01:39 +01:00
Shakker
266d3c8551 refactor: focus external restart verification 2026-07-16 17:01:39 +01:00
Shakker
6013e593c7 fix: narrow unmanaged restart results 2026-07-16 17:01:39 +01:00
Shakker
332b522f90 fix: harden external restart integration 2026-07-16 17:01:39 +01:00
Shakker
333c4f9a61 feat: add restart handoff consume protocol 2026-07-16 17:01:39 +01:00
Shakker
e123606b46 feat: support externally supervised gateway restarts 2026-07-16 17:01:39 +01:00
Shakker
244f4965dc feat: add external gateway supervision policy 2026-07-16 17:01:39 +01:00
Peter Steinberger
8fe4eeea9e fix(exec): stop isolated state dirs from moving live approvals (#108742)
* fix(exec): isolate approval state directories

* chore: drop release-owned changelog entry

* chore: refresh native i18n inventory

* fix(ci): pin XcodeGen for Periphery scans
2026-07-16 08:57:32 -07:00
ooiuuii
6828bcac53 fix(update): verify Windows restart listener owners (#108023)
* fix(update): verify Windows restart listener owners

* fix(update): harden Windows listener ownership checks

Co-authored-by: luyifan <al3060388206@gmail.com>

* fix(update): test shipped Windows listener policy

* ci: refresh merge ref after main schema fix

* ci: refresh merge ref

* fix(lint): drop redundant String conversion in pwsh lookup

* ci: pick up periphery workflow fix

* ci: pick up pinned xcodegen installer

---------

Co-authored-by: Peter Steinberger <steipete@gmail.com>
2026-07-16 07:59:13 -07:00
krissding
eb8cdf6419 fix(cli): add 10s timeout to port-inspection subprocess calls (#108706)
* fix(cli): add 10s timeout to port-inspection subprocess calls

fuser, netstat, and lsof can hang on a busy or misbehaving system.
Node.js execFileSync already supports a timeout option; use 10s to
match the existing convention in debug-claude-usage.ts.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>

* fix(cli): harden port subprocess deadlines

---------

Co-authored-by: Claude Sonnet 4.6 <noreply@anthropic.com>
Co-authored-by: Peter Steinberger <steipete@gmail.com>
2026-07-16 04:33:58 -07:00
Vito Cappello
92075dd72a fix(secrets): inactive web refs no longer block agent turns (#108485)
* fix(secrets): accept inactive refs from partial fallback

* fix(secrets): fail closed on unknown web provider owners

* test(gateway): isolate web secret startup fixtures

---------

Co-authored-by: VACInc <3279061+VACInc@users.noreply.github.com>
Co-authored-by: Peter Steinberger <steipete@gmail.com>
2026-07-16 04:13:40 -07:00
Abner Shang
5ad0d4d6c0 fix: avoid false restart failure during startup migrations (#105544)
* fix: wait for startup migrations on restart

* fix: honor restart readiness caller context

* fix: preserve restart service identity

* fix: refresh readiness context after repair

* fix: bound migration restart wait by wall clock

Co-authored-by: Abner Shang <abner.shang@gmail.com>

---------

Co-authored-by: Peter Steinberger <steipete@gmail.com>
2026-07-16 02:04:49 -07:00
Peter Steinberger
9d4652a46c refactor: make update runtime preflight result explicit (#108760) 2026-07-16 01:48:29 -07:00
Peter Steinberger
dde90a345a refactor(plugin-sdk): narrow wildcard barrels to explicit used exports (#108440)
* refactor(plugin-sdk): narrow wildcard barrels to explicit used exports

* refactor(tools): delete dead tool-planning module exposed by barrel narrowing

* fix(plugin-sdk): restore deprecation tag on OpenClawSchemaType alias

* test(agents): drop test for deleted runtime proxy module

* refactor(tools): trim descriptor types to cache consumers

* refactor(deadcode): harvest exports orphaned by barrel narrowing

* refactor(deadcode): harvest exports orphaned by barrel narrowing (rest)

* fix(agents): restore sdk imports and test markers via public predicate

* fix(plugin-sdk): named type re-exports in plugin-entry; trim types barrel precisely

* chore(plugin-sdk): account unmasked deprecated provider types in budgets

* fix(plugins): name star-only type rows for dts bundling

* fix(plugins): restore host-hook surface; unexport internal api compositions

* fix(plugins): named type imports for api composition; restore needed source exports

* fix(plugins): knip-visible type imports for registry surfaces

* test: adapt tests to privatized media and command internals

* fix(qa-lab): re-export snapshot conversation type

* style: format sessions sdk imports

* fix(plugins): restore smoke entry export; pin budgets to exact actuals

* fix(plugins): canonical smoke-entry import; drop orphaned root shims

* fix(plugins): allowlist manifest probe, repoint qa web import, drop dead browser barrels

* fix(plugin-sdk): pin codex auth marker and scaffold provider type

* fix(qa-lab): keep web-facing model-selection shim within boundary rules

* fix(plugin-sdk): preserve merged contracts through narrowed barrels

* chore(plugin-sdk): pin post-rebase surface budgets
2026-07-16 00:45:23 -07:00
Peter Steinberger
48b11d1c66 fix(update): repair obsolete managed Gateway Node (#108668)
* fix(update): refresh stale managed service Node

* refactor(update): keep preflight result internal

* docs(changelog): defer update note to release
2026-07-16 00:41:43 -07:00
Peter Steinberger
bae9752c5a refactor(deadcode): enforce repository hard zero (#108641) 2026-07-15 22:40:00 -07:00
Peter Steinberger
9c065c895e refactor(cli): split capability commands by domain (#108419)
* refactor(cli): split capability commands by domain

* fix(cli): keep capability metadata type private
2026-07-15 16:57:21 -07:00