* fix(app): graft hardcoded helpers into dynamic tree instead of dropping
pickCommands previously dropped an entire helper subtree whenever a
top-level product name collided with the dynamic overlay. The intent was
to keep the discovery envelope as runtime authority for leaves it
declared, but the side effect was that every helper-only sibling
disappeared too — commands like `chat message send-by-bot`,
`chat message recall-by-bot`, `chat message send-by-webhook`, and
`chat group members add-bot` had silently vanished from the open
edition since the pickCommands introduction, making PR #161's
send-by-bot routing fix unreachable for open-source users.
Switch to cmdutil.MergeHardcodedLeaves for same-named products: the
dynamic side still wins every leaf conflict, and helper-only subtrees
are grafted into the dynamic tree. Envelopes remain authoritative for
leaves they declare; helpers once again fill the gaps they don't.
Verified on a freshly built open-edition binary:
dws chat message send-by-bot --robot-code ... --users ... --text ...
returns a real processQueryKey and routes through canonical_product=bot
via helper_override, matching the v1.0.15 baseline.
* fix(chat,cmdutil): route chat message send by destination flag
`dws chat message send --user <userId>` failed with `不合法的参数` because
the envelope-generated dynamic command maps every destination to the
group-only tool `send_message_as_user`. Only `--group` was viable on the
open edition; single-chat (`--user`, `--open-dingtalk-id`) has never
worked end-to-end.
Fix is in two parts:
1. Add a hardcoded `chat message send` helper that dispatches by
destination flag — `--group` → `send_message_as_user`, `--user` /
`--open-dingtalk-id` → `send_direct_message_as_user`. This mirrors the
closed-source wukong overlay's chatMessageSendCmd so the open edition
lines up with the rest of the product.
2. Let hardcoded leaves opt into overriding the dynamic envelope in
`cmdutil.MergeHardcodedLeaves` when they carry a strictly higher
OverridePriority. The default remains "envelope is authority"; the
opt-in exists for the narrow case where the envelope exposes a single
dispatch path but the hardcoded leaf needs richer flag-based routing
(as here). The new send helper uses preferLegacyLeaf (priority 100)
so it wins against the dynamic leaf.
OverridePriority/SetOverridePriority move to pkg/cmdutil as the new
source of truth; internal/cobracmd/priority.go now delegates so the
annotation key stays single-sourced across the merge layer and helpers.
Verified end-to-end against a freshly built open-edition binary:
send --user 034766 --text … → send_direct_message_as_user → success
send --group <cid> --text … → send_message_as_user → success