Commit Graph

275 Commits

Author SHA1 Message Date
Peter Steinberger
d16e33e08e fix: restore trustworthy end-to-end QA and cross-channel delivery (#115404)
* fix(qa): repair verified end-to-end and channel regressions

* fix(gateway): make interrupted restart recovery lifecycle-safe

* test(heartbeat): target the canonical recovery session store

* fix(gateway): prioritize durable restart recovery before heartbeat

* fix(qa): preserve safe restart recovery and channel expiry

* fix(qa): fail closed and fence restart recovery

* test(agents): isolate restart recovery timing

* test(agents): prove actual restart retry timing

* fix(qa): report incompatible profile scenarios

* fix(scripts): resolve symlinked docker scheduler entrypoints

* fix(qa): require fresh native test evidence

* fix(heartbeat): fence active restart recovery delivery

* fix(gateway): consume untargeted restart acknowledgements

* fix(qa): satisfy exhaustive hosted validation gates

* fix(agents): fence stopped restart recovery dispatch

* style(agents): format restart recovery lifecycle regression

* test(gateway): isolate context prewarm sidecar lifecycle

* test(qa): make scenario process timeout cleanup deterministic

* fix(qa): stamp synthetic gateway configs with current version

* fix(openai): preserve vision capabilities in stale model catalogs

* test(qa): align profile channel rejection with current main

* fix(openai): forward supported moderation for image edits

* fix: restore latest-main CI and image edit documentation

* fix(qa): retain relocated code-mode evidence validation

* fix(openai): expose GPT-5.4 vision in static catalog

* fix(pricing): honor explicit model cost overrides

* test(pricing): keep isolated provider regressions deterministic

* fix(openai): inherit transport for discovered static models

* fix(gateway): honor agent-owned static image capabilities

* test(gateway): preserve prepared-snapshot attachment races

* test(gateway): isolate subagent persistence failure injection

* test(gateway): exercise concurrent voice replay admission

* fix(gateway): restore stale model image capabilities

* fix(agents): publish configured model vision capabilities

* fix(agents): isolate detached media transcript ownership

* test(agents): preserve generic transcript lock regression

* fix(gateway): require proven static model route identity

* fix(qa): accept bounded full-size generated image attachments

* fix(qa): require fresh script producer evidence

* test(qa): prove native E2E scenario execution
2026-07-29 12:45:27 -04:00
Peter Steinberger
1dd1dc1d2b fix(usage): hash pricing fingerprints and retire bloated v1 usage rollups (#115347)
Fix the Gateway OOM from per-row ~2.6 MB catalog fingerprints in issue #115282 by storing a SHA-256 pricing fingerprint instead. Move rollups to the v2 scope, delete v1 rows by scope during prune, add doctor --fix cleanup, and refresh each agent with a single scope read.
2026-07-28 14:27:55 -04:00
qingminlong
a01319b27f fix: account for CJK text in compaction estimates (issue #103930) (#114386)
* fix: account for CJK text in compaction estimates

* fix: share CJK compaction estimator

* fix: format CJK compaction estimator

* fix: make CJK regexes lint-safe

Co-authored-by: qingminlong <qing.minlong@xydigit.com>

---------

Co-authored-by: Peter Steinberger <steipete@gmail.com>
2026-07-27 08:51:44 -04:00
Peter Steinberger
269bc5c89e fix(cli): preserve machine-readable stdout (#113654)
Co-authored-by: 1052326311 <65798732+1052326311@users.noreply.github.com>
2026-07-27 05:44:16 -04:00
Peter Steinberger
5347285d6b improve(models): source pricing from hosted catalog (#114060)
* feat(model-catalog): serve hosted fallback pricing

* refactor(config): retire client pricing bootstrap settings

* refactor(gateway): delete client pricing refresh runtime

* docs(models): explain hosted catalog pricing

* fix(model-catalog): preserve pricing privacy and aliases

* fix(model-catalog): fingerprint pricing eligibility

* fix(model-catalog): harden pricing endpoint checks

* fix(model-catalog): materialize source-safe pricing aliases

* fix(model-catalog): keep unknown pricing fallbacks safe

* fix(model-catalog): reject zero-only hosted prices

* fix(model-catalog): fail closed without pricing policy metadata

* refactor(utils): extract usage pricing normalization

* fix(model-catalog): rebuild policy-owned pricing namespaces

* test(model-catalog): type publisher cost fixtures

* chore(config): regenerate schema baselines

* fix(utils): keep raw pricing tiers private
2026-07-26 03:48:25 -04:00
Peter Steinberger
e94a2e2506 refactor(agents): unify subagent delivery evidence (#113538)
* refactor(agents): unify subagent delivery evidence

* fix(delivery): remove stale context re-export
2026-07-25 00:43:25 -07:00
Peter Steinberger
82d1a03f25 refactor(agents): move implicit-main fallback into load-time roster injection (#112678)
* refactor(agents): require explicit roster defaults

* feat(onboard): create named first roster agent

* refactor(agents): remove runtime main fallbacks

* style(agents): apply roster refactor formatting

* refactor(agents): finish roster-only runtime sweep

* fix(doctor): migrate legacy main session sqlite

* fix(doctor): harden roster session migrations

* fix(onboard): commit first agent atomically

* fix(config): support empty-roster analysis

* fix(agents): preserve legacy main state during creation

* fix(setup): materialize baseline agent roster

* fix(agents): harden legacy default transfer recovery

* fix(agents): simplify roster-only legacy compatibility

* fix(agents): preserve staged first-agent entries

* fix(config): migrate persisted implicit-main rosters

* fix(config): preserve staged empty rosters

* fix(agents): finalize roster-only upgrade paths

* fix(sessions): close legacy main migration outcomes

* fix(config): migrate legacy roster markers at load

* fix(sessions): preserve roster upgrade history

* refactor(sessions): restore lean legacy main compatibility

* fix(setup): prepare first-agent credentials before publish

* fix(config): stabilize roster snapshot migration

* refactor(sessions): shrink legacy main compatibility

* fix(agents): restore roster compatibility fidelity

* fix(sessions): preserve divergent legacy history

* refactor(agents): narrow roster-only scope

* fix(config): isolate roster migration

* test(agents): align roster-only fixtures

* fix(agents): keep main agent undeletable

* fix(agents): harden roster migration invariants

* fix(agents): close setup and audit scope gaps

* fix(cron): scope session reaper throttles by agent

* fix(agents): preserve scoped owner precedence

* fix(config): preserve authored config ownership

* fix(setup): keep default workspace and roster in sync

* fix(setup): preserve default entry workspace on bare runs

* fix(agents): adapt roster rebase to keyed entries

* fix(agents): honor both roster representations

* fix(agents): route roster reads through shared helpers

* fix(config): preserve canonical roster writes

* fix(cron): resolve dynamic default for session reaper

* fix(agents): close dynamic default migration gaps

* fix(agents): align scoped session ownership

* fix(sessions): preserve legacy main directory casing

* fix(agents): align cron and legacy auth ownership

* fix(setup): provision the committed default workspace

* fix(cron): align scoped ownership and reaping

* fix(cron): treat blank agent ids as absent

* fix(cron): retain configured session-store owners

* fix(agents): repair roster-aware CI boundaries

* fix(cron): preserve scoped ownership resolution

* fix(agents): preserve rosterless maintenance paths

* fix(agents): propagate roster ownership through runtime boundaries

* fix(agents): preserve roster ownership across runtime paths

* fix(agents): harden roster diagnostics and legacy routing

* fix(agents): remove redundant diagnostic import

* test(agents): type CLI policy fixture explicitly

* fix(config): preserve canonical roster mutation identity

* fix(doctor): read canonical agent rosters consistently

* fix(config): resolve compound roster unsets safely

* fix(config): finalize main-session reconciliation

* fix(doctor): read canonical session state safely

* fix(sessions): preserve current visibility alias

* fix(config): track roster include provenance

* test(config): type roster provenance cases

* fix(config): refine roster include ownership

* fix(agents): preserve staged roster invariants

* test(config): align fixtures with explicit roster ownership

* test(node-host): preserve optional plan typing

* fix(config): preserve authored roster projections

* test(config): keep raw roster fixtures explicit

* test(config): normalize rosters at runtime fixtures

* fix(config): protect authored roster ownership

* fix(agents): require explicit session ownership

* fix(agents): enforce scoped roster ownership

* fix(sessions): merge fixed-store agent partitions

* fix(agents): harden roster ownership boundaries

* fix(config): reject ambiguous roster projections

* fix(sessions): preserve persisted store ownership

* fix(sessions): keep collision diagnostics additive

* fix(security): scan malformed roster workspaces

* test(config): align snapshot fixtures after rebase

* test(agents): use explicit roster fixtures

* fix(config): harden roster diagnostic boundaries

* fix(sessions): isolate fixed-store agent databases

* test(agents): type malformed default markers

* refactor(sessions): extract store collision resolution

* test(system-agent): split oversized setup coverage

* style(system-agent): format split setup suite

* fix(sessions): preserve promoted store ownership

* fix(sessions): derive scoped owner before target

* fix(sessions): preserve explicit sqlite ownership

* fix(agents): restore roster compatibility across CI

* fix(agents): enforce roster-owned runtime boundaries

* fix(agents): satisfy default lookup lint

* test(sessions): split known-owner coverage

* fix(state): satisfy path identity lint

* fix(agents): preserve malformed roster safety boundaries

* fix(agents): restore roster compatibility at runtime boundaries

* fix(config): satisfy roster boundary type checks

* fix(agents): preserve roster ownership across runtime probes

Setup inference probes now execute as the configured roster owner. Malformed agent-prefixed session rows are intentionally omitted by the fail-closed visibility contract rather than normalized by tests.

* fix(agents): satisfy session list owner lint

* fix(agents): preserve roster-owned runtime boundaries

Restore shared logical rows for exact SQLite session locators while keeping their physical database owner separate. The ownership regression test now constructs an explicit sole-owner database directly instead of relying on first-touch capture, matching the intentional shared-store contract.

* fix(sessions): preserve multiply owned exact stores

* fix(sessions): restore runtime owner boundaries

Keep incognito sentinels agent-owned, fold default-agent approvals into the global snapshot, and preserve the configless legacy-main CLI policy fallback. Also repair the existing CLI watchdog test lifecycle so the compact shard observes its timeout without an unawaited assertion or async timer stall; product behavior is unchanged by that test-only fix.

* test(ci): align owner-scoped fixtures

These assertions are unchanged. The fixtures now declare the intended non-default runner, expose the session-key constant imported by production status code, and select the main approvals bucket explicitly on Windows.

* fix(agents): close final roster ownership gaps
2026-07-24 22:38:09 -07:00
Peter Steinberger
73bba03e4c refactor: canonicalize session delivery state (#113225)
* refactor: canonicalize session delivery state

* test: canonicalize reply persistence fixtures

* test: canonicalize talk delivery fixtures

* test: canonicalize voice session routes

* test: canonicalize attachment delivery fixtures

* test: migrate gateway delivery fixtures

* fix: skip invalid session delivery rows

* test: align delivery SDK surface gates

* fix: preserve legacy delivery precedence

* test: canonicalize heartbeat delivery fixtures

* fix: preserve delivery route prompt identity

* test: canonicalize session delivery fixtures

* fix: preserve recoverable legacy delivery routes

* fix: canonicalize remaining session state

* fix: preserve canonical session classification

* style: format delivery state changes

* test: refresh plugin SDK delivery baseline

* test: avoid mutating session fixture input

* style: simplify delivery identity check

* style: simplify delivery origin spread

* fix: preserve fresh delivery route metadata

* test: assert canonical surface route switch

* fix: canonicalize doctor file-store imports

* fix: preserve transitional delivery migration state

* fix: satisfy canonical delivery CI gates

* ci: scope GitHub App token permissions

* test: infer canonical delivery projections

* test: canonicalize ACP requester delivery fixtures

* test: canonicalize harness rollback fixture

* style: apply pinned formatter
2026-07-24 01:01:19 -07:00
Peter Steinberger
0dd9dcda2f refactor(auto-reply): normalize inbound text once (#113179)
* refactor(auto-reply): canonicalize inbound text once

* chore(plugin-sdk): refresh API baseline

* refactor(auto-reply): narrow finalized template context

* test(auto-reply): keep runner fixtures structurally compatible

* fix(auto-reply): guard optional post-command agent text

* fix(auto-reply): finalize intercepted gateway context

* fix(ci): register iOS release planner entries
2026-07-23 17:39:01 -07:00
Peter Steinberger
edecdbd05e refactor(config): config-surface reduction tranche 3 — product consolidations (review request) (#111527)
* refactor(config): consolidate media model lists

* refactor(config): unify memory configuration

* refactor(config): consolidate TTS ownership

* refactor(config): move typing policy to agents

* refactor(config): retire product-level config surfaces

* refactor(config): share scoped tool policy type

* chore(config): refresh generated baselines

* fix(config): honor agent typing overrides

* fix(config): migrate sibling config consumers

* refactor(infra): keep base64url decoder private

* fix(config): strip invalid legacy TTS values

* chore(config): refresh rebased baseline hash

* fix(doctor): route legacy messages.tts.realtime voice to talk during tts move

* refactor(config): polish final layout names

* refactor(config): freeze retired tuning defaults

* feat(config): add fast mode default symmetry

* refactor(config): key agent entries by id

* docs(config): update final layout reference

* test(config): cover final layout migrations

* chore(config): refresh final layout baselines

* fix(config): align final layout runtime readers

* fix(config): align remaining readers

* fix(config): stabilize final layout migrations

* fix(config): finalize config projection proof

* fix(config): address final layout review

* docs(release): preserve historical config names

* fix(config): complete keyed agent migration

* fix(config): close final migration gaps

* fix(config): finish full-branch review

* fix(config): complete runtime secret detection

* fix(config): close final review findings

* fix(config): finish canonical docs and heartbeat migration

* fix(config): integrate latest main after rebase

* refactor(env): isolate test-only controls

* refactor(env): isolate build and development controls

* refactor(env): collapse process identity indirection

* refactor(env): remove duplicate config and temp aliases

* docs(env): define the operator-facing allowlist

* ci(env): ratchet production variable count

* fix(env): remove stale provider helper import

* fix(env): make ratchet sorting explicit

* test(env): keep test seam in dead-code audit

* test(env): cover ratchet growth and boundary; document surface budgets

* docs(config): document tier-eval consolidations

* docs(config): clarify speech preference ownership

* test(memory): align retired tuning fixtures

* refactor(memory): freeze engine heuristics

* refactor(config): apply tier-eval tranche

* refactor(tts): move persona shaping to providers

* refactor(compaction): move prompt policy to providers

* test(config): align hookified prompt fixtures

* chore(deadcode): classify test-only exports

* chore(github): remove unused spawn helper

* chore(deadcode): classify queue diagnostics

* chore(deadcode): remove unused lane snapshot export

* chore(plugin-sdk): ratchet consolidated surface

* fix(config): integrate latest main after rebase
2026-07-21 20:28:43 -07:00
Peter Steinberger
356bec6f5d fix(usage): price usage rows with the owning agent's model registry (#111389)
* fix: scope usage pricing by agent

* fix(usage): satisfy pricing check gates
2026-07-19 07:57:50 -07:00
Peter Steinberger
264a7b0d12 refactor(channels): consolidate manifest descriptors (#110985) 2026-07-18 23:18:28 +01:00
zengLingbiao
e517d187d2 test(utils): add unit tests for parseJsonWithJson5Fallback (#98801)
* test(utils): add unit tests for parseJsonWithJson5Fallback

* test(utils): verify JSON.parse fast path with spy, per ClawSweeper review

- Add vi.spyOn to prove JSON.parse is called (not JSON5) for strict JSON
- Add spy to prove JSON5.parse is called on fallback path
- Run full src/utils test suite (263 tests passed)
2026-07-17 17:20:16 -07:00
zengLingbiao
f64c35be30 test(utils): add unit tests for safeJsonStringify (#98667) 2026-07-17 17:20:03 -07:00
zengLingbiao
bd966771a7 test(utils): add unit tests for formatTokenCount (#98541)
* test(utils): add unit tests for formatTokenCount

* fix(test): use Number.NaN/Number.POSITIVE_INFINITY per oxlint unicorn/prefer-number-properties

* test(utils): fold formatTokenCount boundary tests into existing usage-format test

Move edge case coverage (invalid inputs, zero/negative, exact boundaries,
thousands overflow) into src/utils/usage-format.test.ts instead of a
separate colocated test file per reviewer feedback.
2026-07-17 17:08:42 -07:00
Peter Steinberger
ec8f6e5e03 feat(browser): add secure per-tab copilot panel (#109817)
* feat(browser): add copilot security contracts

* fix(gateway): expose verified client identity to handlers

* feat(browser): add secure per-tab copilot panel

Co-authored-by: Cameron Beeley <cameron.beeley@gmail.com>

* refactor(browser): separate copilot gateway hint custody

* fix(browser): preserve legacy pairing parse shape

* fix(browser): harden copilot lifecycle custody

Co-authored-by: Cameron Beeley <cameron.beeley@gmail.com>

* fix(browser): enforce copilot lifecycle boundaries

Co-authored-by: Cameron Beeley <cameron.beeley@gmail.com>

* style(browser): format copilot sources

Co-authored-by: Cameron Beeley <cameron.beeley@gmail.com>

* fix(browser): preserve copilot consent revocation

Co-authored-by: Cameron Beeley <cameron.beeley@gmail.com>

* refactor(browser): split copilot custody owners

Co-authored-by: Cameron Beeley <cameron.beeley@gmail.com>

* test(browser): normalize websocket array buffers

Co-authored-by: Cameron Beeley <cameron.beeley@gmail.com>

* chore(protocol): regenerate Swift gateway models

Co-authored-by: Cameron Beeley <cameron.beeley@gmail.com>

* refactor(browser): model copilot runtime entrypoints

Co-authored-by: Cameron Beeley <cameron.beeley@gmail.com>

* fix(browser): honor extension build boundaries

Co-authored-by: Cameron Beeley <cameron.beeley@gmail.com>

* test(gateway): assert targeted chat delivery

Co-authored-by: Cameron Beeley <cameron.beeley@gmail.com>

* test(gateway): cover targeted delivery calls

Co-authored-by: Cameron Beeley <cameron.beeley@gmail.com>

* fix(browser): declare copilot build dependencies

Co-authored-by: Cameron Beeley <cameron.beeley@gmail.com>

* fix(ci): clear browser copilot gate failures

Co-authored-by: Cameron Beeley <cameron.beeley@gmail.com>

* test(ci): cover copilot lint exclusion

Co-authored-by: Cameron Beeley <cameron.beeley@gmail.com>

* fix(browser): gate copilot on relay custody

Co-authored-by: Cameron Beeley <cameron.beeley@gmail.com>

* test(browser): bound copilot relay frames

Co-authored-by: Cameron Beeley <cameron.beeley@gmail.com>

---------

Co-authored-by: Cameron Beeley <cameron.beeley@gmail.com>
2026-07-18 01:00:23 +01:00
Peter Steinberger
03a8a7dd17 refactor(json): share JSON5 fallback parsing 2026-07-14 01:35:48 -07:00
Peter Steinberger
877af700bf feat(codex): continue paired-node Codex catalog sessions from the Control UI (#106927)
* feat(codex): continue paired-node Codex catalog sessions from the Control UI

Codex catalog rows on paired nodes were view-only. Node rows are now
continuable when the node advertises and permits the codex threads.list,
thread.turns.list, and cli.session.resume commands. Continue adopts the
session into a locked codex OpenClaw session (deterministic
harness:codex:node-session key, bounded native-history import, two-phase
initializing marker) and installs a webchat conversation binding
(codex-cli-node-session) through the new generic
bindPluginSessionConversation seam with attempt-ID guarded rollback, so
each web turn runs codex exec resume on the owning node via the existing
inbound_claim path. Local continue/archive semantics are unchanged;
archived rows are no longer offered as continuable.

* fix(plugins): serialize plugin session binds per session

Review P2: the bind rollback checked the attempt id and then awaited the
unbind, so a concurrent Continue could install a newer binding between the
two and lose it to the older attempt's rollback. All session binds for one
session key now queue through an in-process tail, so a failing attempt can
only ever roll back its own binding; the attempt-id guard stays as defense
against out-of-band rebinds.

* refactor(codex): extract node-continue and session-bind modules for the LOC ratchet

Pure movement to satisfy the changed-file TypeScript size ratchet: the
paired-node continue flow moves to session-catalog-node-continue.ts and
session-catalog-node-adoption.ts, catalog paging/parsing helpers to
session-catalog-parsing.ts, the Control UI session-bind seam to
session-conversation-binding.ts (+ session-key helpers), and the internal
conversation-id/channel-prefix helpers to utils. transcript-mirror.ts is
restored to main byte-for-byte; the node history builder constructs a plain
CodexThread (only id is required) instead of widening signatures.

* fix(plugins): satisfy preserve-caught-error in the session-bind rollback

* fix(codex): gate node continue on operator.admin and resume by CLI session id

Second review round: (1) bound node turns pass canMutateCodexHost only for
owners/admins, while sessions.catalog.continue is operator.write — a
write-scoped Control UI client could adopt a node session whose every turn
would then be rejected. The gateway now forwards the caller's scopes to the
provider (SessionCatalogContinueProviderParams.clientScopes) and codex fails
node continues closed without operator.admin, before the dedupe join so a
non-admin cannot ride an admin's in-flight operation. (2) The node binding
stored the app-server threadId, but codex exec resume takes the CLI session
id and forked threads share a session tree where the two differ; the binding
now prefers record.sessionId.

* fix(codex): defer node-session restore until the binding is durable

Third review round: continuing an archived adopted node session unarchived
it before the gateway installed the conversation binding, so a failed bind
left a visible session with no node routing. The unarchive now rides
afterConversationBound; finalizeNodeAdoptedSession already covers both the
initializing and finalized marker states, so the eager restore helper is
deleted.
2026-07-13 19:54:31 -07:00
Vincent Koc
1b43d71440 refactor(channels): privatize approval channel list (#106447) 2026-07-13 22:35:26 +08:00
Vincent Koc
60e8d4f021 refactor(queue): remove dead summary reset (#106440) 2026-07-13 22:14:37 +08:00
Peter Steinberger
26312fd0b0 refactor: remove gateway and channel dead exports (#106038)
* refactor: remove gateway and channel dead exports

* style: format config reload test

* refactor: remove newly dead gateway exports

* test: preserve approval audience coverage

* refactor: preserve gateway contracts while pruning exports

* test: retain gateway regression coverage

* test: restore gateway policy coverage

* test: close dead-export CI gaps

* fix: reconcile dead exports with latest main

* refactor: remove newly dead gateway runner export

* test: remove private worker verifier coverage

* test: preserve weak secret docs coverage

* fix: avoid gateway health import cycle

* fix: preserve node pairing type contract

* style: format talk relay test

* fix: preserve gateway protocol generation contract

* chore: refresh dead export baseline

* fix: preserve loaded target compatibility exports

* fix: preserve plugin SDK declaration resolution

* chore: refresh dead export baseline

* chore: refresh dead export baseline

* test(gateway): derive private worker service options
2026-07-13 05:47:05 -07:00
Peter Steinberger
1136757174 refactor: consolidate bounded concurrency on p-limit and p-map (#106002)
* refactor: adopt p-limit and p-map for bounded concurrency

* chore: normalize lockfile ordering

* fix: preserve memory host concurrency export

* refactor: keep media apply within size budget

* fix: drain memory concurrency before failure

* fix: satisfy memory concurrency guards

* chore: scope memory host dead-code checks

* chore: lower concurrency LOC baselines

* fix: preserve concurrency API surfaces

* chore: reconcile concurrency LOC baseline

* test: keep memory concurrency gate portable

* style: simplify concurrency drain

* ci: refresh deadcode export baseline
2026-07-13 01:53:28 -07:00
Peter Steinberger
e2ec8283c4 refactor(deadcode): trim mid-size src exports (#105888)
* refactor(deadcode): trim auto-reply and CLI exports

* refactor(deadcode): trim cron and task exports

* refactor(deadcode): trim fleet and process exports

* test(deadcode): exercise live task and process seams

* test(fleet): cover stream redaction through owner module

* refactor(security): trim dead internal exports

* refactor(secrets): trim dead internal exports

* refactor(deadcode): trim remaining src exports

* refactor(deadcode): remove test-only runtime exports

* refactor(deadcode): trim pairing test exports

* refactor(deadcode): reconcile refreshed baseline

* test(auto-reply): deduplicate queue state imports
2026-07-13 00:42:56 -07:00
Peter Steinberger
8c7f3d087f refactor: use native abort signal composition (#105947)
* refactor: use native abort signal composition

* style(discord): preserve media module LOC baseline

* chore(ci): lower abort refactor LOC baselines
2026-07-12 22:39:43 -07:00
Peter Steinberger
1b313dc4d4 chore(tooling): enforce indexed access in core tests (#105375)
* test(tooling): enforce indexed access in core tests

* test(tui): constrain theme environment overrides

* test(doctor): enforce indexed access in migration fixtures
2026-07-12 14:29:52 +01:00
Peter Steinberger
d325b6c76b fix: preserve parent abort reasons through timeouts (#105071) 2026-07-12 09:02:12 +01:00
Peter Steinberger
6b95f98fe7 fix(core): make indexed access explicit across remaining src (NUIA phase 3b) (#104773)
* fix(core): make indexed access explicit in auto-reply, infra, and config

Part 1/3 of the src NUIA phase-3b burn-down (#104600): iteration and
destructuring over index reads, boundary guards on parsed input, and
named invariants. Config path walkers bind the path head once; SQLite
migration key handling is hoisted without query-shape changes.

* fix(core): make indexed access explicit in cli, gateway, commands, security, shared

Part 2/3: argv/token selection restructured, gateway event/attachment
invariants named, security parsers stay fail-closed (invariant
violations throw), edit-distance matrices access checked entries.

* fix(core): make indexed access explicit across remaining src surfaces

Part 3/3: channels, plugins, process, cron, plugin-sdk, media, logging,
tui, hooks, daemon, and small directories. Latent bug fixed: a tailnet
resolver could leak undefined through a string|null contract and now
fails with a descriptive local error.

* fix(core): keep optional boundaries optional after per-commit review

Review findings: expectDefined misused where absence is a legitimate
state. CLI --profile/route-args missing next tokens take their existing
miss paths; help normalization compares --help against the last
positional again; first-time plugin install spreads absent cfg.plugins;
denylist scan iterates manifest dependency entries instead of throwing
on omitted sections; tailnet resolver returns a guaranteed string at
the source instead of a caller-side undefined throw.

* refactor(core): closed-key provider labels and honest optional passthroughs

PROVIDER_LABELS becomes a satisfies-typed closed record (static reads
provably defined; dynamic lookups go through providerUsageLabel with
honest string|undefined). Status-scan overview passes its optional
params through unchanged instead of asserting them.

* fix(channels): make getChatChannelMeta honestly optional

The original signature claimed ChatChannelMeta while leaking undefined
on bundled channel id metadata drift; three of four callers already
handled absence. The return type now says so, and the one assuming
caller falls back to the raw channel label.

* fix(core): index-safety for post-rebase main drift

Covers the sqlite-sessions flip and auth-source-plan code that landed
mid-phase, plus the channel-validation test consuming the now honestly
optional getChatChannelMeta.

* refactor(channels): split chat-meta accessors along the SDK contract

getChatChannelMeta keeps its shipped plugin-SDK signature (defined for
bundled ids, fail-loud on impossible misses); new findChatChannelMeta
carries the drift-tolerant optional contract for core auto-enable and
formatting paths.

* fix(qa-channel): own channel metadata instead of a guaranteed-undefined catalog lookup

qa-channel spread getChatChannelMeta over an id that is never in the
bundled catalog, shipping an empty setup meta by accident; the fail-loud
SDK accessor exposed it. The channel now declares its metadata once.

* fix(gateway): heartbeat projection lookahead is optional at the transcript tail

expectDefined wrapped messages[i + 1] whose absence on the final message
is the normal case; the adjacent ternary already handled it. Restores
the plain optional read with an explicit guard in the pair condition.

* fix(plugin-sdk): channel plugin factory tolerates non-bundled channel ids again

createChannelPluginBase spreads bundled catalog meta for ANY channel id,
where absence is the normal case for external plugins; the resolver is
honestly optional again while the exported bundled-id accessor keeps the
fail-loud contract.

* fix(core): spreads of optional config sections stay optional

Fresh-setup and first-install paths (crestodian setup inference, hook
installs, agent config base, target agent models) legitimately lack the
section being rebuilt; spreading undefined is the shipped {} semantics.
Removes the remaining gratuitous assertion wraps found by tree audit.
2026-07-11 20:47:34 -07:00
Peter Steinberger
c48ed95533 feat(ui): merge Instances into a unified Devices page (#104561)
* chore(i18n): regenerate locale bundles for Devices rename

* chore(i18n): regenerate locale bundles for Devices rename

* chore(i18n): sync locale metadata for Devices rename

* fix(gateway): stop tracking ephemeral control-plane clients in presence

* feat(ui): merge Instances into a unified Devices page

* docs: point Instances references at the unified Devices page

* chore(i18n): reconcile locale metadata after rebase

* fix(gateway): keep test-mode clients tracked in presence; refresh docs map
2026-07-11 13:36:07 -07:00
Song Zhenlin
416d113a2c fix(utils): use UTF-16 safe truncation for long URL timeout logs (#104301)
* fix(utils): use UTF-16 safe truncation for long URL timeout logs

* test(utils): cover UTF-16 timeout log boundaries

---------

Co-authored-by: Peter Steinberger <steipete@gmail.com>
2026-07-11 12:27:03 -07:00
Peter Steinberger
1bcc4c5e70 feat(gateway): add cooperative host suspension (#103618)
* feat(gateway): add cooperative suspension preparation

* style: satisfy suspension lint checks

* test(gateway): reset work admission between shared suites

* fix(gateway): reject upgrades during suspension

* fix(gateway): preserve admitted work during suspension

* test(gateway): isolate suspension and restart state

* fix(gateway): close suspension false-ready gaps

* refactor(protocol): slim suspension declaration graph

* refactor(plugin-sdk): sever protocol registry edges

* fix(gateway): preserve admitted restart follow-ups

* fix(gateway): make suspension recovery fail closed

* fix(protocol): keep validation formatter re-export only

* test(gateway): simplify deferred fixture type

* style(gateway): clarify suspension entry name

* fix(gateway): retain detached work admission
2026-07-10 20:24:53 +01:00
Vincent Koc
f79e885985 fix(telegram): harden spooled turn adoption (#103695)
* fix(telegram): harden spooled turn adoption

* fix(telegram): retain fence through adoption

* fix(auto-reply): await queued admission hooks

* fix(telegram): clean up adoption integration

* fix(telegram): break spool retry import cycle

* fix(telegram): serialize spool timeout with adoption
2026-07-10 07:08:35 -07:00
Eva
ae63a48e94 fix(auto-reply): recover stranded message-tool finals by default (#99536)
In messages.visibleReplies "message_tool" sessions, a successful agent turn that produced a substantive private final without calling message(action=send) previously left the user with silence and only an operator log. The gateway now enqueues one protected front-of-queue retry prompting the model to deliver the reply, and falls back to a sanitized visible diagnostic when the retry cannot be enqueued or also strands. Queue overflow protection is unified with the in-flight-aware drop policy (skip in-flight or protected items, reject when nothing is droppable), rejected overflow no longer refreshes the drain debounce, heartbeat turns are excluded from recovery, and recovery retries no longer share the client turn's queued-turn lifecycle.

Fixes #85714

Thanks to Eva (@100yenadmin) for the contribution.
2026-07-10 14:01:01 +05:30
tzy-17
2f7e2aee15 fix(queue): prevent applyQueueDropPolicy from selecting in-flight items as overflow victims (#103284)
* fix(queue): prevent applyQueueDropPolicy from selecting in-flight items as overflow victims

When a burst of inbound messages hits the followup queue cap while the
head item is mid-delivery, applyQueueDropPolicy can select that same
in-flight item as an overflow victim. With the default
dropPolicy: "summarize", the in-flight item ends up recorded in the
overflow summary as dropped even though it is still being delivered,
producing a contradictory record where the same message is both
answered and reported as unanswered-due-to-overflow.

The fix introduces an optional `inFlight` Set parameter to
applyQueueDropPolicy and drainNextQueueItem. The followup queue state
now owns a shared inFlight set that is:
- Populated by drainNextQueueItem during the await run(next) window
- Populated by the collect-merge drain path for activeGroupItems
- Passed to applyQueueDropPolicy in enqueueFollowupRun

The drop policy now computes an effective queue length that excludes
in-flight items, and skips them when selecting splice victims.

Fixes #103246

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>

* fix(queue): align pending depth with active deliveries

---------

Co-authored-by: Claude Opus 4.7 <noreply@anthropic.com>
Co-authored-by: Peter Steinberger <steipete@gmail.com>
2026-07-10 06:53:29 +01:00
ANIRUDDHA ADAK
991262e2e7 fix(utils): fetchWithTimeout ignores caller-provided AbortSignal in RequestInit (#102951)
* fix(utils): fetchWithTimeout ignores caller-provided AbortSignal in RequestInit

* fix(fetch): preserve caller abort through response body

* test(fetch): satisfy abort rejection lint

* test(mattermost): satisfy promise executor lint

---------

Co-authored-by: Aniruddha Adak <aniruddhaadak80@users.noreply.github.com>
Co-authored-by: Peter Steinberger <steipete@gmail.com>
2026-07-10 00:39:18 +01:00
Peter Steinberger
5ef269c2bb fix: keep bounded Unicode text valid across UTF-16 boundaries (#102823)
* fix(text): keep bounded output UTF-16 safe

Co-authored-by: 黄剑雄0668001315 <huang.jianxiong@xydigit.com>
Co-authored-by: 0668000539 <shu.zongyu@xydigit.com>
Co-authored-by: 张鹊平0668001085 <zhang.queping@xydigit.com>
Co-authored-by: 赵旺0668001248 <zhao.wang1@xydigit.com>
Co-authored-by: 陈宪彪0668000387 <chen.xianbiao@xydigit.com>
Co-authored-by: lizeyu-xydt <li.zeyu@xydigit.com>

* chore(changelog): defer release note to automation

* refactor(qa-lab): keep text helper behind SDK

---------

Co-authored-by: 黄剑雄0668001315 <huang.jianxiong@xydigit.com>
Co-authored-by: 0668000539 <shu.zongyu@xydigit.com>
Co-authored-by: 张鹊平0668001085 <zhang.queping@xydigit.com>
Co-authored-by: 赵旺0668001248 <zhao.wang1@xydigit.com>
Co-authored-by: 陈宪彪0668000387 <chen.xianbiao@xydigit.com>
Co-authored-by: lizeyu-xydt <li.zeyu@xydigit.com>
2026-07-09 15:21:23 +01:00
Bryan Tegomoh, MD, MPH
3d442153f6 fix(agents): avoid false unscheduled note after shell cron add (#101807)
* fix(agents): count shell cron reminder adds

* fix(agents): narrow shell cron reminder tracking

* fix(agents): handle shell runner variants

---------

Co-authored-by: Vincent Koc <vincentkoc@ieee.org>
2026-07-07 14:45:10 -07:00
Vincent Koc
f565138ddc refactor(deadcode): localize core helpers (#101869) 2026-07-07 13:16:57 -07:00
Vincent Koc
2e7ffca8ff fix(core): preserve UTF-8 byte truncation boundaries 2026-07-04 17:48:21 -07:00
Dallin Romney
194dd6fe50 refactor(security): consolidate secret primitives (#99746)
* refactor(security): consolidate secret primitives

* fix(plugin-sdk): align secret display metadata

* chore(plugin-sdk): refresh API baseline after rebase

* refactor(security): trim secret primitive consolidation
2026-07-04 16:38:13 -07:00
Dallin Romney
1a04c9c2ad refactor: consolidate string reader mechanics (#99676)
* refactor: consolidate string reader mechanics

* fix: declare model catalog normalization dependency

* fix: keep model catalog dependency-free

* refactor(core): keep string readers internal
2026-07-03 18:00:07 -07:00
Dallin Romney
c7aca4f029 refactor: consolidate async timing helpers (#99721) 2026-07-03 17:58:15 -07:00
Peter Lee
4abdf0f3b5 fix(logging): redact Telegram bot tokens from timeout URLs (#99428)
* fix(net-policy): redact Telegram bot tokens from timeout URLs

* fix(net-policy): extend Telegram bot token redaction to all hostnames

* refactor(net-policy): centralize bot token URL redaction

---------

Co-authored-by: Peter Steinberger <steipete@gmail.com>
2026-07-03 05:05:38 -07:00
Yuval Dinodia
150ca2fedd fix(agents): keep merged delivery routes account-bound (#98240)
* fix(agents): keep merged delivery routes account-bound

mergeDeliveryContext gated route-field crossing on channel only, so a
completion origin that knew its account but not a concrete target
inherited a different account's to/threadId on the same channel. A
subagent, cron, or media completion for bot-a could be addressed to
bot-b's chat but sent through bot-a (cross-account misroute) or dropped.

This restores the account-bound guard added in 1ed8592467 and removed as
collateral by 025db6cf9e (PR #89949); same-account and missing-account
merges still backfill so the media route-pin path is preserved. Restores
the deleted regression test.

* fix(agents): centralize account-bound completion routes

---------

Co-authored-by: Peter Steinberger <steipete@golden-gate.local>
2026-06-30 18:32:35 -07:00
zengLingbiao
09ebc1d566 test(utils): add unit tests for chunkItems (#98219)
Add 8 test cases covering fixed-size array splitting, empty input,
size <= 0, size=1, size > length, exact division, readonly input
preservation, and fractional size behavior.
2026-06-30 18:15:24 -07:00
ly-wang19
6285f5c776 fix(utils): keep reply directive ids unicode-safe (#96938)
* fix(utils): keep reply directive ids unicode-safe

* test(utils): catch trailing lone surrogate in hasUnpairedSurrogate helper

Per PR #96938 review: the test helper missed a high surrogate at end of
string because charCodeAt(out-of-bounds) returns NaN, and NaN comparisons
are always false. Guard bounds explicitly so the truncation test actually
proves what it claims, plus two cases pinning helper behavior.

* chore(utils): rerun QA smoke to confirm memory-index timeout flake on #96938

---------

Co-authored-by: ly-wang19 <ly-wang19@users.noreply.github.com>
2026-06-30 17:47:39 -07:00
lin-hongkuan
2906d6c38f fix(auth): strip controls from masked API keys (#96445)
* fix(auth): strip controls from masked API keys

* test(auth): cover DEL and C1 masked key controls

* chore: retrigger PR checks

---------

Co-authored-by: lin-hongkuan <lin-hongkuan@users.noreply.github.com>
2026-06-29 11:15:55 -07:00
lin-hongkuan
bc7f0f1223 fix(secrets): strip control characters from secret input (#96444)
* fix(secrets): strip control characters from secret input

* chore: retrigger PR checks

* fix(web-content): strip controls from provider secrets

---------

Co-authored-by: lin-hongkuan <lin-hongkuan@users.noreply.github.com>
2026-06-29 10:51:08 -07:00
linhongkuan
8f9beb7766 fix(reply): sanitize explicit reply directive ids 2026-06-28 18:51:38 -07:00
linhongkuan
31e941c3fc fix(context): count fullwidth chars in token estimates (#96442) 2026-06-25 14:36:04 +08:00
Peter Steinberger
025db6cf9e fix(agents): pin media requester route at task start 2026-06-23 00:09:20 +05:30