* feat(nodes): route alerts by active computer
* fix(ci): allowlist node presence mobile coverage
* test(prompts): refresh node presence snapshots
* fix(macos): await presence reporter actor hop
* fix(macos): type presence test delivery state
* docs(nodes): add active presence guide
* docs(nodes): format presence troubleshooting
* improve(ui): compact the new-session screen on phones
The /new target controls condense on phones: Where and Worktree share one
line and the folder picker takes its own full-width line below, so long
paths stay readable instead of stacking three loose rows. The shared
welcome hero (start screen and /new) scales down on phones so the
composer and recent chats fit the first screenful, and the /new scroll
inset matches the chat thread's mobile padding.
* fix(ui): keep mobile target rows in DOM order
Review caught that order: 2 on the folder chip made visual and tab order
diverge on phones. The folder chip now flexes next to Where with a 140px
floor that pushes Worktree to the second line, so the compact layout
keeps visual, reading, and focus order aligned.
* fix(ui): wrap the worktree fields with their toggle
Groups the worktree toggle and its branch/name fields in one flex unit so
line breaks never separate the dependent fields from the toggle at any
width; review caught that the previous flex sizing let the branch control
wrap alone on wider phones.
* fix(tlon): cap SSE payload JSON.parse at 16 MiB to prevent OOM
* fix(tlon): cap SSE stream buffer and JSON.parse at 16 MiB to prevent OOM
* chore(tlon): add production-style SSE bounded proof script (#101274)
Adds extensions/tlon/proof-sse-bounded.mts which drives the real
UrbitSSEClient.processStream and processEvent against Node Readable streams
(not unit-test mocks) to demonstrate:
- normal SSE events are still delivered through the stream path;
- an unterminated stream that would grow beyond 16 MiB is rejected before
unbounded accumulation;
- a single SSE payload above 16 MiB is rejected before JSON.parse.
The script passes on this branch and fails 2/3 assertions when run against
origin/main's sse-client.ts, providing the before/after proof ClawSweeper
requested.
* chore(tlon): fix oxlint catch type in proof script (#101274)
* fix(tlon): reject oversized SSE chunk before buffer concatenation
Move the stream byte-limit check before buffer += chunkStr so a
single oversized chunk never lands in the pending buffer. The old
guard ran after concatenation, which still allowed the memory spike
this hardening is meant to prevent.
Add a single-oversized-chunk test to prove the guard fires before
the chunk is concatenated into the pending buffer.
Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
* chore(tlon): remove PR-specific SSE bounded proof script
The proof script was review-only validation for #101274. Durable behavior
coverage lives in sse-client.test.ts (stream buffer bounding, oversized
chunk rejection before concatenation, 16 MiB boundary, normal delivery,
1000 small events). Per ClawSweeper P3 finding, drop the one-off script
from the plugin tree.
* fix(tlon): bound SSE event buffering safely
* test(tlon): avoid unsafe optional chaining
* fix(tlon): count split Unicode at SSE limit
* fix(tlon): parse split SSE delimiters at limit
---------
Co-authored-by: Claude Opus 4.7 <noreply@anthropic.com>
Co-authored-by: Peter Steinberger <steipete@gmail.com>
The /new draft page now renders the same welcome block as the empty-chat
start screen, with the draft controls folded in launcher-style: hero on
top, a quiet borderless target row (agent, node, folder, worktree)
directly above the mid-screen composer, and the recent chats below. The
page reuses renderWelcomeState via hint/composer slots so the surfaces
cannot drift apart; the shell treats /new as a chat-like route that owns
its scrolling, with the top inset doubling as the native titlebar drag
band. The welcome is content-sized on this route so a tall draft (open
folder browser, short window) stays scrollable from the top. Also
repairs the stale new-session e2e heading wait (the h1 was removed in
Closes#105068
* fix(slack): log typing reaction errors instead of silently swallowing them
The typing reaction (emoji) add and remove calls both use empty catch
handlers, silently discarding all errors. If the bot token lacks
reactions:write scope, the operator has no way to diagnose why the
configured typing reaction never appears.
Replace the empty catch with logVerbose calls that record the Slack
error, matching the existing logging pattern in the same file.
* test(slack): cover typing reaction failures
---------
Co-authored-by: Peter Steinberger <steipete@gmail.com>
* fix(extensions): make indexed access explicit across channel plugins
Transport-payload-safe burn-down: malformed Telegram/Discord/QQ/LINE
and sibling channel input keeps existing skip paths; no synthesized
fields, no new throws in delivery loops. Zalo escape sentinels preserve
literal matches instead of undefined replacements.
* fix(extensions): make indexed access explicit across provider and memory plugins
Stream and model iteration, tool-block guards, capture guards, and
sparse accumulators; singleton model reads carry named invariants.
* fix(extensions): make indexed access explicit across tooling plugins, flip the extensions lane
Remaining plugins (oc-path, qa-lab, browser, logbook, and siblings) plus
the tsconfig.extensions.json flag flip. Cleanup: logbook sampleFrames
NaN index at max=1, QA retry clamp at non-positive attempts, dead Canvas
probe and OpenShell no-op slice removed, twitch test setup leak excluded
from the prod lane.
* refactor(plugin-sdk): expose expectDefined via a focused SDK subpath
Extensions imported @openclaw/normalization-core directly, crossing the
external-plugin packaging boundary (it only worked because the runtime
builder bundles undeclared workspace helpers). expect-runtime joins the
canonical entrypoints JSON, generated exports, API baseline, docs, and
subpath contract test; all 78 extension imports now use the SDK seam.
Two scanner-shaped locals renamed for review-bundle hygiene.
* chore(plugin-sdk): raise surface budgets for the expect-runtime subpath
One new entrypoint with one callable export, added intentionally as the
packaging-honest seam for extension invariant helpers.
Adds a core sessions_search agent tool backed by a SQLite FTS5 index that
lives next to the transcript rows in the per-agent database. Indexing is
transactional: user/assistant text is indexed inside the same write
transaction that persists the event, deletes drop index rows in the same
transaction, and branch rewinds mark the session dirty so the next search
rebuilds it from the same visible-path resolution sessions_history uses
(which also lazily backfills doctor-migrated databases). Search executes
gateway-side behind an additive sessions.search method with a bounded
session-key allowlist; visibility, sandbox restrictions, and snippet
redaction mirror sessions_history.
Closes#100978