* feat(firecrawl): add keyless Firecrawl Search (Free) provider + richer firecrawl_search options
Add an opt-in, keyless 'firecrawl-free' web_search provider (Firecrawl
Search (Free)) mirroring the Parallel plugin's parallel-free pattern:
requiresCredential false, no autoDetectOrder, never auto-selected. The
free path is credential-isolated — it never resolves or sends any
Firecrawl API key (no Authorization header), so opting out of credentials
cannot leak a configured/paid key — and its results and cache key carry a
distinct 'firecrawl-free' provider identity. The keyed 'firecrawl'
provider and core search auto-select behavior are unchanged, honoring the
maintainers' opt-in policy for keyless search.
Registered in index.ts, the web-search-provider barrel, the
web-search-contract-api metadata artifact (the onboarding/setup source),
manifest contracts, the official external plugin catalog snapshot, and
the doctor/contract registries.
Also extend the firecrawl_search tool to /v2/search parity:
includeDomains/excludeDomains (mutually exclusive), tbs, location,
country, and raise the result cap to 100.
* docs: regenerate docs_map for firecrawl heading rename
---------
Co-authored-by: developersdigest <jonathan@sideguide.dev>
* feat(tooling): enforce noUncheckedIndexedAccess in the scripts lane
Burns down all 153 scripts-lane errors (bench aggregation, release
checks, i18n inventories, argv indexing) and flips the flag in
tsconfig.scripts.json. Direct-Node-executed release harness scripts use
local narrowing instead of workspace imports, which do not resolve
under plain node execution. Benchmark measured loops untouched.
* fix(scripts): import expect helpers via relative package sources
tsconfig path aliases resolve from cwd under tsx, so release wrapper
scripts running against old release target cwds could not resolve
@openclaw/normalization-core (not a linked root dependency). Relative
package-source imports match the established pattern on the adjacent
lines and are cwd-independent; old-target planning verified directly.
* 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.
Drops the last non-doctor whole-store resolveSessionStoreEntry read in the
reply pipeline; exact working-set key plus accessor disk read match the
sibling refresh sites in runPreparedReply. Part of #104219 (seam 8).
* refactor(sessions): migrate runtime storage to sqlite
* test(sessions): fix sqlite CI regressions
* test(sessions): align remaining sqlite fixtures
* fix(codex): require sqlite trajectory recorder
* test(sessions): align orphan recovery sqlite fixture
* test(sessions): align sqlite rebase fixtures
* fix(sessions): finish current-main integration of the sqlite flip
Resolve the whole-store SDK removal across its owner boundary: drop the
loadSessionStore re-export and the registry whole-store wrappers, wire
hasTrackedActiveSessionRun into gateway chat, complete the
preserveLockedHarnessIds cleanup contract, flip the codex thread-history
import to storePath targets, and port remaining main-side tests from
file-store helpers to session accessor reads.
* chore: drop committed pebbles log, revert plugin-inspector bump, refresh generated docs
Remove the 1.8k-line .pebbles/events.jsonl work log from the branch, restore
the plugin-inspector advisory lane to main's pinned 0.3.10 so the supply-chain
bump gets its own review, and regenerate docs_map, the plugin SDK API baseline,
and the export-surface ratchet for the merged tree.
* feat(sessions): keep archived transcripts by default with zstd cold storage
Codex-style retention: deleting or resetting a session archives its
transcript as a zstd-compressed JSONL artifact (plain when the runtime
lacks node:zlib zstd) and keeps it until the disk budget evicts oldest
first. resetArchiveRetention now governs both deleted and reset archives
and defaults to keep; maxDiskBytes defaults to 2gb so retention stays
bounded, with archives evicted before live sessions. The cron reaper
follows the same knob instead of deleting archives on its own timer.
* fix(state): converge agent DB migration lineages and bound database growth
Merge coherence: run both structure-gated legacy memory-schema repairs
(flip-lineage drop, main-lineage identity rebuild) before the flip
migration so pre-flip v1/v2 and pre-merge flip v1/v4 databases all
converge, and hoist foreign_keys=OFF outside the schema transaction
where the pragma was silently ignored and the v1 sessions rebuild
cascade-deleted session_entries.
Growth guards: fresh agent DBs enable auto_vacuum=INCREMENTAL, WAL
maintenance releases freed pages in bounded passes (never a blocking
full VACUUM), and doctor reports state/agent DB bloat from freelist
stats.
* fix(codex): resolve the store path for thread-history import via the SDK
The supervision catalog passed the legacy sessionFile locator to the
storePath-targeted transcript mirror; resolve the agent store path with
the session-store SDK helper instead of a runtime-object seam so test
fakes and headless callers need no extra surface. Drop the obsolete
missing-session-id preprocessing case: sessions rows are NOT NULL on
session_id and upsert repairs id-less patches at write time.
* fix(sessions): fail safe on malformed disk-budget config and doctor stat errors
A malformed explicit maxDiskBytes disables the budget instead of
falling back to the destructive 2gb default the user never chose, and
the doctor bloat check skips databases whose paths stat-fail instead of
aborting doctor.
* fix(sessions): complete sqlite conflict translations
* test(sqlite): align hardening checks with maintenance
* test(sessions): inspect compressed transcript archives
* fix(tests): await session seeds and drop unused helpers flagged by CI lint
The five unawaited writeSessionStoreSeed calls raced their SQLite seeds
against the assertions, failing compact shards; the bloat probe drops a
useless initializer and the merged tests drop now-unused helpers.
* test(sessions): type legacy proof events directly
* test(sessions): align hardening contracts
* perf(sessions): read usage transcript sizes from SQL aggregates
Usage/cost scans walked every session and materialized every transcript
event just to re-stringify it for a byte estimate — the #86718 stall
class reborn on the DB. readTranscriptStatsSync sums stored JSON bytes
in SQLite without loading a single row.
* fix(sessions): re-root foreign-root transcript paths onto the current sessions dir
Restored backups, moved OPENCLAW_STATE_DIR, and rehearsal copies carry
absolute sessionFile paths from the old root; the containment fallback
kept those foreign paths, so migration read (and would archive) files in
the original root and reported local copies missing. Re-root the
canonical agents/<id>/sessions suffix onto the current dir when the file
exists there; genuine cross-root layouts still fall through unchanged.
* test(agents): seed harness admission through sqlite
* fix(sqlite): close agent db on pragma setup failure
* fix(doctor): compact and retrofit incremental auto-vacuum after session import
The migration is the sanctioned offline window: post-import compact
reclaims import churn and applies auto_vacuum=INCREMENTAL to databases
created before the fresh-DB pragma existed, so runtime maintenance can
release pages in bounded passes on every install.
---------
Co-authored-by: Peter Steinberger <steipete@gmail.com>
* chore(lint): enforce no-floating-promises repo-wide
* feat(tooling): split DOM globals out of the Node-side typecheck program
tsconfig.core.json now compiles src/ + packages/ with lib ES2023; new
tsconfig.ui.json owns ui/ with DOM. Web-global names used by Node code
alias to canonical undici/stream-web types; highlight.js loads through a
validated narrow API because its d.ts force-includes lib.dom. Boundary,
sparse-guard, changed-lane routing, and profile lanes cover the new ui
graph.
* chore(deps): declare undici-types and teach knip about the highlight.js runtime require
* ci: retrigger dropped pull_request synchronize event
* refactor(types): derive web-global aliases from @types/node fetch globals, drop undici-types dep
* ci: retrigger after dependency guard cleared
* fix(scripts): add ui lane to changed-lanes declaration union
* chore(types): add declaration files for scripts/lib and scripts/e2e modules
* chore(types): add declaration files for top-level script modules (a-m)
* chore(types): add declaration files for top-level script modules (n-z)
* test: use a non-secret-shaped gateway token fixture
* test: type ci workflow guard helpers for the root test lane
* chore(tooling): typecheck root test/** with a dedicated tsgo lane
- test/tsconfig/tsconfig.test.root.json: root-test program (strict unused checks,
fixtures excluded; two Docker E2E clients that import built dist/** stay out,
same rationale as the scripts/e2e exclusion in tsconfig.scripts.json)
- tsgo:test:root wired into tsgo:test, check:test-types, scripts/check.mjs, and
the ci.yml test-types shard, mirroring the tsgo:scripts lane (#104348)
- changed-lane routing: test/**/*.ts (excluding fixtures) and the lane tsconfig
now trigger 'typecheck test root' in check:changed; previously test/ paths ran
lint only, so harness type errors surfaced first in CI (#104287 envDir case)
- burn down all 1071 latent type errors in the program: precise param/local
types across test/scripts, test/vitest, test/e2e, and transitive scripts/e2e
program members; 205 sibling .d.mts declaration files for imported .mjs
modules (committed separately); zero any, zero ts-expect-error
- resolve the pre-existing testing star-export ambiguity in
scripts/e2e/parallels/common.ts with an explicit re-export
Closes#104388
* chore(types): correct declaration fidelity per structured review
- re-derive 51 .d.mts files from implementation data flow instead of
initializers: fix a wrong never return (runTestProjectsDelegation returns
the child), add encoding-sensitive exec/spawn overloads (plain-gh), restore
the full release profile union, make parsed paths string | null, add missing
parseArgs fields via help/non-help unions, add a missing sibling declaration
(budget-number-args), drop 15 unused lint directives
- precise install-record/tuple typing removes the type-aware oxlint
regressions the first declarations caused in scripts/e2e implementations
- route .mts declaration edits under test/ to the testRoot lane and reference
the test-root project from tsconfig.projects.json so tsgo:all covers it
(closes both review findings against the lane wiring)
* chore(scripts): keep telegram runner dist typing structural for the boundary guard
* chore(types): declare runtime pack and gateway readiness exports added on main
* test: pin the importTargetPlan form of the plugin-contract plan import
The guard expectation still referenced the raw await import( form that
7ae5996bb3 (#103975) replaced with the importTargetPlan fallback helper;
the assertion fails on current main.
* origin/main:
fix(cron): abort superseded reconciliation hooks (#104368)
ci(release): expose Telegram runtime preflight stage (#104387)
fix(status): avoid false shell-wrapper audit warnings (#81778)
fix: retry live Gateway readiness proof (#104374)
fix(exec-approval): stop misattributing Allow Always unavailability to policy (#97740)
fix: preserve Mac bundle during live builds (#104376)
chore(docs): translate with GPT-5.6 xhigh
test: wire Control UI suite into CI, fix its broken tests, drop dead harness surface (#104361)
fix(ui): hide group submenu separator when New group is the only entry (#104370)
fix(discord): reset progress drafts across queued turns (#102341)
docs(cli): clarify that exec-policy show and approvals get exclude per-session /exec overrides (#94999)
fix(discord): single-source thread-binding default placement and guard artifact parity (#104342)
fix(agents): add tool-activity heartbeat to keep subagent alive during tool calls (#95536)
fix(maint): reuse recent same-PR hosted gates (#104355)
* test: wire Control UI suite into CI, fix its broken tests, drop dead harness surface
- fix 7 Control UI tests broken on main: module-mock factories are unreliable
under isolate:false shared workers; use RealtimeTalkSession prototype spies
and real jsdom storage instead (chat-realtime, chat-pull-requests)
- add gated checks-ui CI job (runUiTests changed-scope output): chromium
provisioning, lint:ui:no-raw-window-open, pnpm --dir ui test; ~30s on a
4vcpu runner, runs only when ui-affecting paths change
- add weekly node22-compat workflow exercising the supported lower Node bound
with the same command set as the dispatch-only ci.yml job
- delete the unreachable channels entry in EXTENSION_TEST_CONFIG_ROUTES and
the never-populated extensionRoutedChannelTestFiles override machinery
(born empty in 2ccb5cff22); resolved globs are provably identical
- guard run-vitest.mjs hardcoded path maps with existence tests so renames
cannot silently drop extended stall watchdogs
- remove unenforced coverage thresholds; test:coverage is informational, docs
updated (reference/test, help/testing, plugins/sdk-testing)
Closes#104321
* test: pin OPENCLAW_CI_RUN_UI_TESTS in the manifest env expectation
* test(ui): capture the realtime start spy instead of referencing the unbound prototype method
* test(ui): raise ui vitest timeouts for real-browser layout tests on small CI runners
* feat(tooling): add tsgo typecheck lane for scripts/**
* fix(scripts): burn down scripts type debt surfaced by the new lane
Typing-only except bugs the lane surfaced: gh-read timeout race,
Discord Headers spread dropping entries, undefined allowedHeadBranches
match, plugin-boundary matchAll crash. Deletes retired config keys from
fixtures/benches (prompt snapshots regenerated, config dump only) and
the orphaned non-runnable sync-moonshot-docs script. Adds full-surface
.d.mts declarations for existing .mjs boundaries.
* test: fix changed-run routing, dedupe gateway package lanes, repair force-rerun triggers
- route extensions/active-memory changed runs to their dedicated lane; add a
generic guard that every catch-all-excluded extension root resolves to a
dedicated config so future split lanes cannot silently skip changed tests
- exclude packages/gateway-client and packages/gateway-protocol from the unit
lane; explicit targets now route to the gateway-client lane (was double-run)
- generate forceRerunTriggers from the test/vitest directory and resolve all
entries absolute: Vitest matches triggers against absolute changed-file
paths, so the old hand-maintained relative list never matched at all
- replace deprecated envFile:false with envDir:false (Vitest 4.1.9 warning)
- give scripts/test-live.mjs stall detection teeth: kill the process group and
exit non-zero when OPENCLAW_VITEST_NO_OUTPUT_TIMEOUT_MS elapses quietly
- consolidate the live-docker shell target list into changed-lanes.mjs so the
lane regex and check targets cannot drift; cover subagent-announce edits
- delete orphans: vitest.extension-clickclack.config.ts,
vitest.full-core-unit.config.ts, scripts/test-docker-all.sh,
scripts/test-live-acp-spawn-defaults-docker.sh
Closes#104231
* test: keep envDir literal so sharedVitestConfig satisfies Vite UserConfig
Vite 8 types envDir as string | false; the bare object literal widened false to
boolean and broke check:test-types at the defineConfig call sites.