* feat(cli): add `sessions compact` command and fail loudly on CLI `/compact`
`sessions.compact` was reachable only as an internal Gateway RPC — no CLI
command, no docs — and `openclaw agent --message '/compact'` silently no-opped
with exit 0 because the slash-command handler rejects CLI-originated senders,
so the message fell through to an ordinary agent turn that compacted nothing.
- Add `openclaw sessions compact <key>` wrapping the existing `sessions.compact`
RPC; exit non-zero on a transport error or an `ok:false` payload so automation
never mistakes a silent no-op for success.
- Reject `openclaw agent --message '/compact'` with a redirect to the new
command and exit 1 instead of a silent exit 0. The shared chat-side `/compact`
handler is left untouched (no compatibility / message-delivery blast radius).
- Strictly validate `--max-lines` and `--timeout` (positive integers only).
- Document the command and the `sessions.compact` RPC in docs/cli/sessions.md.
Fixes#90640.
* fix(cli): inherit parent `sessions` options for `compact`
`openclaw sessions compact <key>` did not merge the parent `sessions`
command options the way its sibling subcommands (list/cleanup/info/…) do,
so a parent-level `--agent`/`--json` was silently dropped. In particular
`openclaw sessions --agent work compact <key>` compacted the default
agent's session instead of the work agent's — a wrong-target session-state
mutation.
Merge the parent options in the compact action (parent `--agent`/`--json`,
with the compact-level option taking precedence) and add regression
coverage for parent `--agent`, parent `--json`, and the compact-level
override.
Refs #90640.
* fix(cli): report pending Codex compaction and reject unsupported parent options
Address two ClawSweeper review findings on the `sessions compact` command:
- `sessions-compact.ts`: the Codex app-server `thread/compact/start` path
returns `ok:true / compacted:false` with a pending marker, meaning the
compaction was *started* asynchronously. The formatter collapsed every
non-compacted success into "No compaction needed", so Codex users were told
nothing happened. Report it as a started/pending compaction instead.
- `register.status-health-sessions.ts`: the parent `sessions` command defines
list-only options (`--store`/`--all-agents`/`--active`/`--limit`) that the
compact action previously ignored. Silently dropping a parent `--store` is
dangerous — the gateway resolves the target store itself, so a user could
believe they targeted one store while another is mutated. Reject any
unsupported inherited parent option with a clear error and a non-zero exit.
Add regression tests for the pending-compaction message and the rejected
parent options.
Refs #90640.
* fix(gateway): guard sessions.compact maxLines truncation against active runs
The non-maxLines (LLM) compact branch interrupts an active session run before
compacting, but the maxLines truncate branch read the tail, archived, and
overwrote the transcript in place without that guard. Exposing `--max-lines`
as a documented CLI command (this PR) would make the active-run data-loss mode
tracked by #72765 easy to trigger from ordinary CLI usage.
Run the same interruptSessionRunIfActive guard in the maxLines branch before
reading the tail and truncating, matching the LLM compact path. Add gateway
regression coverage over a real in-process Gateway: with no active run, the
maxLines branch truncates the on-disk transcript 500 -> 50 and preserves the
original 500 lines in the .bak archive; with an active embedded run, the
maxLines branch fires the same interrupt (abort + wait-for-end) before
archiving and truncating.
* docs(cli): move sessions compact section above related links
The new "Compact a session" section was inserted between the cleanup
section's inline "Related:" list and the page's final "## Related"
block, splitting related-link content around the command docs. Move the
compact section above the related-links area and merge the orphaned
"Session config" link into the single final "## Related" block.
* fix(gateway): avoid no-op compact aborts
Signed-off-by: sallyom <somalley@redhat.com>
* fix(gateway): satisfy compact preflight lint
Signed-off-by: sallyom <somalley@redhat.com>
* fix(sessions): preserve compacted transcript structure
---------
Signed-off-by: sallyom <somalley@redhat.com>
Co-authored-by: sallyom <somalley@redhat.com>
Co-authored-by: Peter Steinberger <steipete@gmail.com>
Summary:
- The PR adds descriptor-backed CLI command suggestions for unknown root commands, wires them into Commander parse errors and early unowned-root diagnostics, and covers both paths with focused CLI tests.
- PR surface: Source +104, Tests +71. Total +175 across 5 files.
- Reproducibility: yes. for the behavior gap: current main's formatter and early unowned-root path emit generic diagnostics without closest-command hints, and the PR proof shows the after-fix CLI output.
Automerge notes:
- PR branch already contained follow-up commit before automerge: fix: suppress suggestions for plugin policy diagnostics
- PR branch already contained follow-up commit before automerge: Merge remote-tracking branch 'origin/main' into fix/83999-cli-command…
- PR branch already contained follow-up commit before automerge: test: align agent model expectations
- PR branch already contained follow-up commit before automerge: test: restore unrelated agent test fixture
Validation:
- ClawSweeper review passed for head b98f5b59e6.
- Required merge gates passed before the squash merge.
Prepared head SHA: b98f5b59e6
Review: https://github.com/openclaw/openclaw/pull/91345#issuecomment-4646215016
Co-authored-by: Glenn-Agent <glenn_agent@163.com>
Address ClawSweeper P1 (Carry the effective git channel into finalize):
an unconfigured git/source update runs the core update on the git/dev channel
(runGatewayUpdate: opts.channel ?? "dev"), but the finalizer received no channel
and fell back to the stable package channel, so plugin convergence could resolve
official plugins on the wrong channel.
Mirror the CLI post-core resume's effective/requested channel split: the RPC
finalize path now passes the effective channel (configChannel ?? DEFAULT_GIT_CHANNEL)
to update finalize via OPENCLAW_UPDATE_EFFECTIVE_CHANNEL (convergence-only), never
as --channel. update finalize uses it as a convergence fallback but never persists
update.channel unless the user actually requested one.
Clarify that `openclaw mcp list`, `show`, `set`, and `unset` manage the OpenClaw `mcp.servers` registry and do not include the separate mcporter registry.
Co-authored-by: Alix-007 <li.long15@xydigit.com>
Replace the hardcoded Mattermost-only open-DM config check with a generic,
plugin-agnostic warning driven by a single shared evaluator
(evaluateDmPolicyAllowFromDependency) reused by the Zod refinements and the
CLI validator. Surface warnings at 'config validate' and on config load.
Remove the Mattermost-specific status-issues module now covered generically;
keep the runtime drop-log diagnostic.
* fix(cron): clear delivery routing fields from cron edit
cron edit could set delivery channel/to/thread-id/account but could not unset them: an empty value (e.g. --to "") builds delivery.X = undefined, which is omitted from the JSON-RPC patch, so mergeCronDelivery never sees the key and the field is silently kept. The gateway RPC already accepts an explicit null to clear each field (CronDeliveryPatchSchema + mergeCronDelivery via normalizeOptionalString); the CLI just never sent it.
Add --clear-channel/--clear-to/--clear-thread-id/--clear-account, each emitting null (mirroring the existing --clear-model), with mutual-exclusion guards against the matching set flag and against --webhook.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
* fix(cron): preserve delivery defaults when clearing routes
* fix(cron): validate cleared prefixed routes
---------
Co-authored-by: ly-wang19 <ly-wang19@users.noreply.github.com>
Co-authored-by: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Co-authored-by: Vincent Koc <25068+vincentkoc@users.noreply.github.com>
When a child openclaw process is spawned via a backgrounded subshell that
exits before the new process reaches the stale-pid sweep, the new process
is reparented to the supervisor (PID 1 / launchd) and the ancestor walk
in getSelfAndAncestorPidsSync can no longer see the running gateway. The
running gateway then shows up on lsof as an unrelated sibling on the
port and gets SIGKILL'd by cleanStaleGatewayProcessesSync, recreating
the issue #68451 supervisor restart loop across a reparent boundary.
Real-world trigger: a user ~/.zshrc auto-start block
if ! pgrep -x openclaw-gateway >/dev/null; then
(openclaw gateway >/dev/null 2>&1 &)
fi
combined with codex per-turn `zsh -c "set -e; . shell_snapshot"` invocations
caused every chat turn on rh-bot to SIGKILL its launchd-managed gateway,
producing HTTP 000 errors and ~33 kill events captured by a forensic
launchd unified-log tracker before the zshrc was patched.
Fix: gateway-cli captures OPENCLAW_GATEWAY_SERVICE_PID from inherited env
BEFORE overwriting it with process.pid, then threads the captured PID
through cleanStaleGatewayProcessesSync into getSelfAndAncestorPidsSync's
exclusion set. The protection is opt-in per call site so existing
maintainer paths (openclaw update / openclaw doctor restart helpers) keep
their ability to terminate a running gateway intentionally.
The inherited-PID parser is strict positive-integer only: a malformed
inherited env value (`"123abc"`, `"123.4"`, `"0x7b"`, etc.) is rejected
rather than silently protecting PID 123 from cleanup and leaving the
stale listener alive. New focused unit tests cover the parser
contract.
Existing regression tests cover the reparent suicide-kill scenario and
the defensive ignore-non-positive-PID contract on the cleanup side.