* 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.
* fix(signal): clean up signal-cli download temp dir on every exit path
installSignalCliFromRelease created a temp dir with fs.mkdtemp for the
download archive but never removed it. Every return path — including the
success return and the extraction-failure / binary-not-found errors — leaked
the directory plus the downloaded archive (signal-cli Linux-native archives
are ~50-130 MB). Repeated installs or retries accumulated multi-hundred-MB
temp dirs under the preferred tmp dir.
Wrap the body after mkdtemp in try/finally that recursively removes the temp
dir. The extracted binary is installed under CONFIG_DIR and is unaffected.
Co-Authored-By: Claude <noreply@anthropic.com>
* style(signal): drop unnecessary String() conversion in test spy
dir is already a string (mkdtemp return); String(dir) triggers the
no-unnecessary-type-conversion lint rule.
Co-Authored-By: Claude <noreply@anthropic.com>
* test(signal): cover success-path temp dir cleanup with real archive
Add a success-path test that mocks the network fetch to return a real tar.gz
archive (containing a signal-cli binary) so installSignalCliFromRelease runs the
full download -> extract -> find-binary -> chmod path against real bytes, then
asserts the temp dir and downloaded archive are removed by the finally clause.
This complements the existing error-path test so both exit paths are covered.
Co-Authored-By: Claude <noreply@anthropic.com>
* fix(signal): use owned temp download workspace
* fix(signal): allow bounded native extraction
---------
Co-authored-by: Claude <noreply@anthropic.com>
Co-authored-by: Peter Steinberger <steipete@gmail.com>
* feat(signal): add target aliases
* fix(signal): canonicalize alias delivery targets
* fix(signal): harden alias target resolution
* test(signal): cover formatted media aliases
* test(signal): align approval alias proof with request shape
* Reuse Signal alias map for directory listing
* fix(signal): guard containerRestRequest JSON.parse against malformed responses
Wrap JSON.parse(text) in containerRestRequest with try/catch to prevent a malformed Signal REST container response from throwing an unhandled SyntaxError.
On parse failure, throw a descriptive Error. The success body is already bounded by readProviderTextResponse (16 MiB cap, D1 protection).
Co-Authored-By: Claude <noreply@anthropic.com>
Signed-off-by: lsr911 <liao.shirong@xydigit.com>
* fix(signal): add real HTTP server proof for malformed JSON guard
Starts a local node:http server returning malformed JSON, then calls
containerRestRequest against it. This exercises the actual changed
try/catch code path through the real fetch stack (no mock override).
Proof output:
PASS malformed JSON: throws Error :: type=Error
PASS malformed JSON: message describes malformed JSON
PASS malformed JSON: NOT raw SyntaxError
Signed-off-by: lsr911 <liao.shirong@xydigit.com>
Co-Authored-By: Claude <noreply@anthropic.com>
Signed-off-by: lsr911 <liao.shirong@xydigit.com>
* test(signal): remove committed proof script
---------
Signed-off-by: lsr911 <liao.shirong@xydigit.com>
Co-authored-by: Claude <noreply@anthropic.com>
Co-authored-by: Vincent Koc <vincentkoc@ieee.org>
Wrap the signal outbound sanitizeText hook with sanitizeAssistantVisibleText so assistant internal tool-trace scaffolding is stripped before delivery, matching the sibling channel fixes under #90684 (Telegram #95774, Google Chat #95084, IRC #97214).
Replace bare `await response.json()` in `installSignalCliFromRelease` with
`readProviderJsonResponse` (16 MiB cap, stream cancel on overflow). The
external GitHub Releases endpoint can include a large `body` changelog field;
the error path was already guarded but the success path was unbounded.
The existing inner catch continues to convert overflow errors into the
graceful `{ ok: false, error: "Failed to parse signal-cli release info." }` path.
Adds a regression test verifying the stream is cancelled before all chunks are
read on an oversized 20 MiB streaming response.
Co-authored-by: NIO <nocodet@mail.com>
Co-authored-by: Cursor <cursoragent@cursor.com>
* chore(release): close out 2026.6.10 on main
* chore(release): align native app metadata for 2026.6.10
* chore(release): sync Android 2026.6.10 notes
* docs(changelog): preserve 2026.6.9 history
* docs(changelog): preserve 2026.6.9 history
Fix render-aware markdown chunking so `Number.POSITIVE_INFINITY` is treated as an explicit unbounded chunk limit instead of falling back to `1`.
This preserves full Signal media captions and disabled Signal text chunking while keeping invalid non-finite limits on the existing fallback path.
Fixes#92734.
Thanks @yhterrance for the report and fix.