* fix(install): reject runtimes with broken npm
* test(installer): use real Node for npm selection
---------
Co-authored-by: Peter Steinberger <steipete@gmail.com>
* feat(mattermost): add thread.requireExplicitMention to opt out of thread auto-follow
Mattermost treats any reply in a thread the bot has participated in as an
implicit mention, so requireMention only gates the first message and the bot
then answers follow-ups addressed to other people for the participation TTL.
Slack exposes channels.slack.thread.requireExplicitMention for exactly this;
Mattermost had no equivalent and its strict schema rejected the key.
Add channels.mattermost.thread.requireExplicitMention (channel + per-account),
mirroring Slack. When set, thread participation no longer counts as a mention.
Default (unset/false) keeps today's auto-follow behavior unchanged.
Related: #108269
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
* feat(channels): add implicit mention policy foundation
* feat(channels): unify implicit mention policy
Co-authored-by: leon <dodoma0919@gmail.com>
* refactor(channels): keep implicit policy inside evaluator
* fix(channels): use exported implicit mention type
* chore(channels): satisfy extension lint
* fix(config): break implicit mention type cycle
* fix(plugin-sdk): account for implicit mention config export
* refactor(config): isolate implicit mention schema
* chore(plugin-sdk): align implicit mention surface budget
* fix(config): remove unused schema re-export
---------
Co-authored-by: leon <dodoma0919@gmail.com>
Co-authored-by: Claude Opus 4.8 <noreply@anthropic.com>
Co-authored-by: Peter Steinberger <steipete@gmail.com>
* fix(ci): address reviewer findings across the perf-lever batch
Seven follow-ups from Codex review feedback on the landed CI perf PRs:
docker packaging switches to the full build profile (the ciArtifacts
step env clobbered its canonical-dts requirement); the boundary sticky
restore gates on generative source tree OIDs in both lanes, making
restored artifacts valid by construction (kills the clock-skew mtime
false-skip and ghost declarations from deleted sources); the node-test
worker budget derives from nproc instead of the runner label (labels
over-promise under load) and keeps the 2-worker cap when plans can
overlap; the deadcode task falls back to serial Knip below 8 cores;
the lint-lane i18n verify also runs for any ui-touching diff (keys are
extracted from all ui sources, not just ui/src/i18n); the oxlint
concurrency diagnostic moves to stderr; and workspace packages join
the prompt-snapshot always-run surface.
* fix(ci): fingerprint every generative source the boundary artifacts consume
Autoreview flagged inputs outside the tree-OID gate; toolchain, config,
and script inputs were already covered by the sticky key hash, but the
old actions/cache key also fingerprinted src/plugins/types.ts and
src/video-generation sources the OID list missed. Add those plus
src/channels (the plugin-sdk declaration graph reaches its public
types) to the fingerprint in all three sites.
* fix(ci): fold runner toolchain identity into the boundary sticky fingerprint
Autoreview: the sticky key hashes config/scripts/package.json/lockfile,
but a node/pnpm toolchain bump (pinned in the workflow, not the key)
could leave the key unchanged and bless artifacts built with the prior
toolchain. Record node/pnpm versions alongside the source tree OIDs in
all three fingerprint sites so a toolchain-only change forces a cold
build.
The generated hand-edited d.mts declared pruneOrphanLocaleDocs twice
with resolveClawHubRepoPath between them, tripping the
adjacent-overload-signatures lint on every PR. Keep the documented
declaration.
* feat(android): add Wear proxy protocol
Introduce a bounded, versioned phone/watch RPC contract and wire its test, lint, and build gates before either runtime endpoint lands.
Co-authored-by: Sebastian Schubotz <git@sibbl.de>
* test(android): lock Wear wire names
Cover every supported RPC method and event discriminator so phone and watch cannot silently drift.
Co-authored-by: Sebastian Schubotz <git@sibbl.net>
* fix(android): bound Wear JSON depth
Reject excessively nested Data Layer envelopes before kotlinx.serialization can recurse through them.
* fix(android): enforce Wear depth on encode
Keep outbound messages inside the same JSON nesting contract enforced by the decoder.
* fix(android): preflight Wear payload depth
Traverse arbitrary JSON payloads iteratively before serialization so deeply nested local trees fail safely.
* feat(android): add Wear phone proxy
Co-authored-by: Sebastian Schubotz <git@sibbl.net>
* fix(ci): repair Wear and docs sync checks
---------
Co-authored-by: Sebastian Schubotz <git@sibbl.de>
Co-authored-by: Sebastian Schubotz <git@sibbl.net>
* test(slack): drop rotating loading-message fixture expectations
* refactor(slack): drive progress drafts through the shared compositor
Slack's status_final progress path now uses the shared channel compositor
(preamble headline, reasoning, tools, plan checklist, commentary
arbitration) instead of its hand-rolled gate/merge/render pipeline, and
native task cards consume compositor snapshots with stable row identity
(line ids first, fixed reasoning id, occurrence-suffixed content hashes).
Finals in progress mode post as fresh messages that follow the draft's
thread; the working draft then collapses into a compact activity receipt,
while failed or error finals leave the draft as the turn record. The
rotating native loading messages are gone in favor of the plain typing
status. Queued and assistant-boundary turns re-arm with clean delivery
state, and native completion status survives transient append failures.
* test: fix environment-dependent failures on built and partial-clone checkouts
Canvas A2UI fixtures now pin the resolved root through a new canvas
test-api hook: dev checkouts with a locally built a2ui.bundle.js won
candidate resolution and shadowed the fixture root. Speech-core prefs
tests resolve the canonical tmpdir (macOS /tmp symlink breaks fs-safe
store roots), and the bundled plugin install test asks discovery for
the canonical bundled path instead of hardcoding the source tree.
* fix(release): keep evidence verifier blob reads local-deterministic
git show against a forged or missing SHA lazily fetched from the
promisor remote on partial clones, hanging a security check on network
state (266s observed). GIT_NO_LAZY_FETCH pins verification to local
objects; missing blobs fail closed as before.
* perf(test): pay the command-handler barrel once and merge subagent command tests
commands-name and commands-login imported the full handler barrel
(~1,700 modules) for registration assertions; those now live in a
dedicated registration test, dropping the two files from 12.6s/4.6s to
1.4s/1.0s locally. Five subagent command test files merged into one so
the auto-reply module graph evaluates once instead of five times.
* perf(ci): stripe node test bins by measured file cost
Round-robin striping packed the whale files together, leaving
auto-reply-commands-1 at ~220s while sibling stripes idled at ~30s.
Greedy LPT over advisory per-file seconds hints balances the commands,
cli-runner, and tooling stripes deterministically; group hints for the
restriped bins are equalized at the old totals.
* perf(ci): run the deadcode Knip scans concurrently
check-dependencies spent ~194s running seven Knip child processes
strictly serially (three package scripts, each iterating its scans).
The scans are independent processes over separate configs: both
deadcode scripts now Promise.all their scans, the CI task launches the
three package scripts concurrently with buffered logs, and the lane
moves to the 16 vCPU class for core/memory headroom. The
missing-exports-script contract violation now fails fast before
launching scans. Local: unused-files 218% CPU, 37s wall.
* test(ci): align prerelease plan with the 16 vCPU dependencies lane
* perf(ci): unblock parallel oxlint shards and gate the lint-lane i18n verify
check-lint is the slowest static lane (median 252s): the control-UI
i18n verify runs 86s unconditionally and the three oxlint shards run
serially (89s) because the parallel gate demands 48GB of memory — a
local-Mac threshold that Blacksmith's 32GB 16 vCPU class can never
meet. CI now parallelizes shards at 8+ cores / 24GB+, and the lint case
reuses the existing run_control_ui_i18n manifest gate so diffs that
cannot affect generated catalogs skip the verify while oxlint always
runs.
* chore(ci): print oxlint shard concurrency decision
The lint-lane validation run still executed shards serially on a 16
vCPU runner; one log line exposes the resolved concurrency and the
host resources the decision saw.
The gateway already broadcasts stream:"plan" agent events with typed
{step, status} snapshots; all three clients dropped them. Control UI now
renders an expandable checklist bar above the composer (run-scoped,
cleared on run lifecycle); the shared iOS/macOS chat UI mounts a
Liquid Glass pill (iOS 26 glassEffect, material fallback) between the
message list and composer; Android adds an expandable pill above the
composer bridged through ChatController/NodeRuntime/MainViewModel.
All parsers accept typed and legacy string steps, enforce the
single-in_progress invariant, and scope snapshots and clears to the
owning run. Locale artifacts, Android resources, and the iOS string
catalog carry generated translations for the pill strings.