* feat(gateway): add skills.search and skills.detail RPC methods
Expose ClawHub search and detail capabilities through the Gateway protocol,
enabling desktop/web clients to browse and inspect skills from the registry.
New RPCs:
- skills.search: search ClawHub skills by query with optional limit
- skills.detail: fetch full detail for a single skill by slug
Both methods delegate to existing agent-layer functions
(searchSkillsFromClawHub, fetchSkillDetailFromClawHub) which wrap
the ClawHub HTTP client. No new external dependencies.
Signed-off-by: samzong <samzong.lu@gmail.com>
* feat(skills): add ClawHub skill search and detail in Control UI
Add skills.search and skills.detail Gateway RPC methods with typed
protocol schemas, AJV validators, and handler implementations. Wire
the new RPCs into the Control UI Skills panel with a debounced search
input, results list, detail dialog, and one-click install from ClawHub.
Gateway:
- SkillsSearchParams/ResultSchema and SkillsDetailParams/ResultSchema
- Handler calls searchClawHubSkills and fetchClawHubSkillDetail directly
- Remove zero-logic fetchSkillDetailFromClawHub wrapper
- 9 handler tests including boundary validation
Control UI:
- searchClawHub, loadClawHubDetail, installFromClawHub controllers
- 300ms debounced search input to avoid 429 rate limits
- Dedicated install busy state (clawhubInstallSlug) with success/error feedback
- Install buttons disabled during install with progress text
- Detail dialog with owner, version, changelog, platform metadata
Part of #43301
Signed-off-by: samzong <samzong.lu@gmail.com>
* fix(skills): guard search and detail responses against stale writes
Signed-off-by: samzong <samzong.lu@gmail.com>
* fix(skills): reset loading flags on query clear and detail close
Signed-off-by: samzong <samzong.lu@gmail.com>
* fix(gateway): register skills.search/detail in read scope and method list
Add skills.search and skills.detail to the operator READ scope group
and the server methods list. Without this, unclassified methods default
to operator.admin, blocking read-only operator sessions.
Also guard the detail loading reset in the finally block by the active
slug to prevent a transient flash when rapidly switching skills.
Signed-off-by: samzong <samzong.lu@gmail.com>
* fix(skills): guard search loading reset by active query
Signed-off-by: samzong <samzong.lu@gmail.com>
* test: cover ClawHub skills UI flow
* fix: clear stale ClawHub search results
---------
Signed-off-by: samzong <samzong.lu@gmail.com>
Co-authored-by: Frank Yang <frank.ekn@gmail.com>
* feat(gateway): make chat history max chars configurable
* fix(gateway): address review feedback
* docs(changelog): note configurable chat history limits
config.patch unconditionally writes the config file and sends SIGUSR1
even when diffConfigPaths detects zero changed paths. This causes a
full gateway restart (~10s downtime, all SSE/WebSocket connections
dropped) on every control-plane config.patch call, even when the
config is identical — e.g. a model hot-apply that doesn't change any
gateway.* paths.
Fix: when changedPaths is empty, return early with `noop: true`
without writing the file or scheduling SIGUSR1. The validated config
is still returned so the caller knows the current state.
This lets control-plane clients safely call config.patch for
idempotent updates without triggering unnecessary restarts.
* feat(gateway): implement claim check pattern to prevent OOM on large attachments
* fix: sanitize mediaId, refine trimEnd, remove warn log, add threshold and absolute path
* fix: enforce maxBytes before decoding and use dynamic path from saveMediaBuffer
* fix: enforce absolute maxBytes limit before Buffer allocation and preserve file extensions
* fix: align saveMediaBuffer arguments and satisfy oxfmt linter
* chore: strictly enforce linting rules (curly braces, unused vars, and error typing)
* fix: restrict offload to mainstream mimes to avoid extension-loss bug in store.ts for BMP/TIFF
* fix: restrict offload to mainstream mimes to bypass store.ts extension-loss bug
* chore: document bmp/tiff exclusion from offload whitelist in MIME_TO_EXT
* feat: implement agent-side resolver for opaque media URIs and finalize contract
* fix: support unicode media URIs and allow consecutive dots in safe IDs based on Codex review
* fix(gateway): enforce strict fail-fast for oversized media to prevent OOM bypass
* refactor(gateway): harden media offload with performance and security optimizations
This update refines the Claim Check pattern with industrial-grade guards:
- Performance: Implemented sampled Base64 validation for large payloads (>4KB) to prevent event loop blocking.
- Security: Added null-byte (\u0000) detection and reinforced path traversal guards.
- I18n: Updated media-uri regex to a blacklist-based character class for Unicode/Chinese filename support, with oxlint bypass for intentional control regex.
- Robustness: Enhanced error diagnostics with JSON-serialized IDs.
* fix: add HEIC/HEIF to offload allowlist and pass maxBytes to saveMediaBuffer
* fix(gateway): clean up offloaded media files on attachment parse failure
Address Codex review feedback: track saved media IDs and implement best-effort cleanup via deleteMediaBuffer if subsequent attachments fail validation, preventing orphaned files on disk.
* fix(gateway): enforce full base64 validation to prevent whitespace padding bypass
Address Codex review feedback: remove early return in isValidBase64 so padded payloads cannot bypass offload thresholds and reintroduce memory pressure. Updated related comments.
* fix(gateway): preserve offloaded media metadata and fix validation error mapping
Address Codex review feedback:
- Add \offloadedRefs\ to \ParsedMessageWithImages\ to expose structured metadata for offloaded attachments, preventing transcript media loss.
- Move \erifyDecodedSize\ outside the storage try-catch block to correctly surface client base64 validation failures as 4xx errors instead of 5xx \MediaOffloadError\.
- Add JSDoc TODOs indicating that upstream callers (chat.ts, agent.ts, server-node-events.ts) must explicitly pass the \supportsImages\ flag.
* fix(agents): explicitly allow media store dir when loading offloaded images
Address Codex review feedback: Pass getMediaDir() to loadWebMedia's localRoots for media-uri refs to prevent legacy path resolution mismatches from silently dropping large attachments.
* fix(gateway): resolve attachment offload regressions and error mapping
Address Codex review feedback:
- Pass \supportsImages\ dynamically in \chat.ts\ and \gent.ts\ based on model catalog, and explicitly in \server-node-events.ts\.
- Persist \offloadedRefs\ into the transcript pipeline in \chat.ts\ to preserve media metadata for >2MB attachments.
- Correctly map \MediaOffloadError\ to 5xx (UNAVAILABLE) to differentiate server storage faults from 4xx client validation errors.
* fix(gateway): dynamically compute supportsImages for overrides and node events
Address follow-up Codex review feedback:
- Use effective model (including overrides) to compute \supportsImages\ in \gent.ts\.
- Move session load earlier in \server-node-events.ts\ to dynamically compute \supportsImages\ rather than hardcoding true.
* fix(gateway): resolve capability edge cases reported by codex
Address final Codex edge cases:
- Refactor \gent.ts\ to compute \supportsImages\ even when no session key is present, ensuring text-only override requests without sessions safely drop attachments.
- Update catalog lookups in \chat.ts\, \gent.ts\, and \server-node-events.ts\ to strictly match both \id\ and \provider\ to prevent cross-provider model collisions.
* fix(agents): restore before_install hook for skill installs
Restore the plugin scanner security hook that was accidentally dropped during merge conflict resolution.
* fix: resolve attachment pathing, defer parsing after auth gates, and clean up node-event mocks
* fix: resolve syntax errors in test-env, fix missing helper imports, and optimize parsing sequence in node events
* fix(gateway): re-enforce message length limit after attachment parsing
Adds a secondary check to ensure the 20,000-char cap remains effective even after media markers are appended during the offload flow.
* fix(gateway): prevent dropping valid small images and clean up orphaned media on size rejection
* fix(gateway): share attachment image capability checks
* fix(gateway): preserve mixed attachment order
* fix: fail closed on unknown image capability (#55513) (thanks @Syysean)
* fix: classify offloaded attachment refs explicitly (#55513) (thanks @Syysean)
---------
Co-authored-by: Ayaan Zaidi <hi@obviy.us>