Commit Graph

465 Commits

Author SHA1 Message Date
Peter Steinberger
ccb147518c feat(agents): Swarm core — collector spawn, agents_wait, structured output, caps (gated) (#110932)
* docs: add Swarm implementation spec

* feat(agents): Swarm core — collector spawn, agents_wait, structured output, fastMode, caps

Implements docs/plan/swarms.md §4-6: tools.swarm config gate (default off),
collector-mode sessions_spawn (collect/outputSchema/fastMode/groupId), fail-closed
child approvals, agents_wait race-semantics tool, per-group FIFO scheduler with
maxConcurrent/maxChildrenPerGroup/maxTotalPerGroup caps, additive registry and
state-schema columns (no schema-version bump), and colocated tests.

Part of #110325

* fix(agents): rebase reconciliation — preserve swarm state columns

* fix(agents): O(1) collector session index, cheap-first preflight, collector start lifecycle hooks

Autoreview findings: replace the per-request full registry scan with an
index-maintaining run map and gate the persisted-store fallback behind
isSubagentSessionKey; emit subagent_progress/subagent_spawned from the swarm
scheduler start callback so collector children produce balanced plugin
lifecycle events.

* chore(protocol): regenerate Swift gateway models for swarm fields

* fix(agents): lint cleanup — typed catch, explicit microtask flush, no executor return

* fix(agents): knip/test-support/max-lines cleanup for swarm surfaces

* fix(agents): keep tool-catalog ui-safe — callers pass prepared swarmEnabled fact

resolveSwarmConfig value-import in tool-catalog dragged the server graph into
the Control UI bundle via tool-policy-shared (UNLOADABLE_DEPENDENCY on
subpath aliases). Catalog stays pure; the gateway tools-catalog handler
resolves the gate and passes the boolean.

* fix(agents): reconcile swarm spawn pipeline

* fix(agents): refresh swarm tool metadata

* fix(apps): sync swarm tool localization

* style(agents): compact tool display metadata

* fix(plugin-sdk): account for swarm config surface
2026-07-18 23:30:11 -07:00
Peter Steinberger
756a491a51 fix(speech): strip markdown before TTS and route code-heavy replies sensibly (#110948)
The talk.speak synthesis path passed raw agent text to providers, so talk
mode could read fenced code, links, and tables aloud. Speech normalization
now happens once at the shared synthesis boundary (speech-mode stripMarkdown:
label-only links, decorative bullet/glyph cleanup, punctuation collapsing).
Code-heavy replies (>=50% fenced content, CommonMark-aware scanner incl.
blockquote/list containers and unclosed fences) get routed by surface:
talk.speak speaks a short on-screen fallback line, channel auto-TTS skips
the voice note since the visible text already carries the content, and
explicit conversions (tts.convert, tagged hidden TTS, chat Listen) always
speak stripped best-effort content.
2026-07-18 18:16:43 -07:00
cxbAsDev
593423ecc0 fix(shared): bound ignore-file reads during workspace scans (#101429)
* fix(shared): bound ignore-file reads during workspace scans

* fix(shared): import bounded reader through infra policy wrapper

* fix(shared): preserve chained-symlink ignore files while bounding reads

* fix(shared): correct ignore-rules test calls and remove dead return

* fix(shared): restore ignore matcher return value from addIgnoreRules

* fix(shared): fail closed on oversized ignore files during scans

* style(shared): format ignore-rules signature

* test(shared): rename misleading under-cap ignore-file test

* chore: retrigger CI for unrelated flaky run-with-env shutdown test

* fix(shared): make oversized ignore-file exclusion terminal

* test(shared): remove loadSkillsFromDir dependency for main compat

* chore: retrigger dead-code scan after Periphery/Homebrew flake

* fix(scans): fail closed on ignore read races

* fix(scans): treat fail-closed ignore paths literally

Co-authored-by: 陈宪彪0668000387 <chen.xianbiao@xydigit.com>

* fix(scans): preserve native ignore path semantics

Co-authored-by: 陈宪彪0668000387 <chen.xianbiao@xydigit.com>

* fix(scans): bound ignore rule amplification

Co-authored-by: 陈宪彪0668000387 <chen.xianbiao@xydigit.com>

* fix(scans): preserve case-insensitive fail-closed matching

Co-authored-by: 陈宪彪0668000387 <chen.xianbiao@xydigit.com>

* fix(scans): preserve bounded ignore composition

Co-authored-by: 陈宪彪0668000387 <chen.xianbiao@xydigit.com>

* fix(scans): satisfy matcher method binding lint

Co-authored-by: 陈宪彪0668000387 <chen.xianbiao@xydigit.com>

* fix(scans): preserve ignore matcher case mode

Co-authored-by: 陈宪彪0668000387 <chen.xianbiao@xydigit.com>

* fix(scans): keep matcher options internal

Co-authored-by: 陈宪彪0668000387 <chen.xianbiao@xydigit.com>

* fix(scans): require matcher case contract

Co-authored-by: 陈宪彪0668000387 <chen.xianbiao@xydigit.com>

---------

Co-authored-by: Peter Steinberger <steipete@gmail.com>
Co-authored-by: Peter Steinberger <peter@steipete.me>
2026-07-18 15:31:42 +01:00
tzy-17
a941d3ab72 fix(shared): reject HTTP status codes outside the 100-599 range (#110554)
* fix(shared): reject HTTP status codes outside the 100-599 range

extractHttpStatusMatch only checked Number.isFinite, so 3-digit
sequences such as "000", "099", "600", and "999" were accepted as
valid HTTP statuses. Downstream code then surfaced them as "HTTP 0"
in user-visible messages and fed them into retry/classification
branches (e.g. isCloudflareOrHtmlErrorPage checks `code < 500` and
`code < 600`). Restrict the extracted code to the IANA HTTP status
code range (100-599).

Co-authored-by: Patrick Erichsen <patrick.a.erichsen@gmail.com>

* fix(shared): validate all parsed HTTP status prefixes

---------

Co-authored-by: Patrick Erichsen <patrick.a.erichsen@gmail.com>
Co-authored-by: Peter Steinberger <steipete@gmail.com>
2026-07-18 10:44:31 +01:00
Peter Steinberger
d7de67ae02 feat: ask_user follow-ups — harness convergence, channel finalization + reactions, native cards, docked web panel (#110372)
* feat(ask-user): follow-up harness slice

* feat(ask-user): follow-up channels slice

* feat(ask-user): follow-up native slice

* feat(ui): dock question panel above composer with stepper and compact stream summaries

* docs: refresh follow-up integration maps

* test(ui): align terminal summary proof

* fix(infra): echo declared option answers in terminal status when free-text is allowed

* fix(infra): keep reaction answering when display labels are formatter-adjusted

* fix(agents): settle plain-text claims only after question registration commits

* fix(agents,apps): commit-ordered claim persistence, claim-aware prompt delivery, non-blocking question refresh

* fix(harness,infra): reaction-appropriate question copy, caller presentations honored

* fix(native,infra,agents): local-expiry eviction, value-addressed reactions, reserve-before-request

* fix(infra,android): dual-mode question resolver for compact callbacks; reset terminal retention on replayed pending

* fix(harness,discord): claim-aware prompt delivery in run helper; escape finalization labels

* fix(macos): merge transient-content visibility with question cards after main sync

* fix: repair ask user follow-up CI

* test: update limited bootstrap scope expectation

* fix: retain shared question card API

* chore: refresh native i18n inventory
2026-07-18 03:32:39 -04:00
dwc1997
ec3eb573bf test(shared): add unit tests for numeric coercion helper (#98663)
* test(shared): add unit tests for numeric coercion helper

* test(shared): cover numeric coercion boundaries

---------

Co-authored-by: Peter Steinberger <steipete@gmail.com>
2026-07-18 07:17:34 +01:00
Peter Steinberger
746d257f05 feat: contract sessions-family tool outputs (#110424)
* feat(agents): contract sessions-family tool outputs

* refactor(agents): remove unused fast-mode exports
2026-07-18 06:43:12 +01:00
Peter Steinberger
92e8e8bca6 test: move deferred-event-buffer test to its packages/ai owner and drop dead protocol test 2026-07-17 17:36:48 -07:00
zengLingbiao
2666cf7174 test(shared): add unit tests for createDeferredEventBuffer (#98670) 2026-07-17 17:21:18 -07:00
zengLingbiao
256a2ece73 test(shared): add unit tests for modelKey (#98795) 2026-07-17 17:20:59 -07:00
zengLingbiao
1d64790bf2 test(shared): add unit tests for normalizeNodePresenceAliveReason (#98802)
* test(shared): add unit tests for normalizeNodePresenceAliveReason

* fix(test): add missing bg_app_refresh and significant_location assertions
2026-07-17 17:19:54 -07:00
zengLingbiao
ec35d6b5ba test(shared): add unit tests for agent liveness state helpers (#98546) 2026-07-17 17:09:02 -07:00
zengLingbiao
58a86297f8 test(shared): add unit tests for parseConfigPathArrayIndex (#98543) 2026-07-17 17:08:50 -07:00
Wynne668
f104c51e85 fix(clawhub): reject calendar-invalid feed timestamps (#106942)
* fix(clawhub): reject calendar-invalid feed timestamps

* fix(clawhub): preserve strict feed timestamps

* fix(test): avoid promise executor return in clack prompter test

Co-authored-by: Cursor <cursoragent@cursor.com>

* fix(clawhub): preserve feed timestamp semantics

* fix(clawhub): strengthen feed timestamp validation

Co-authored-by: ZengWen-DT <ceng.wen@xydigit.com>

* fix(time): validate full end-of-day fractions

Co-authored-by: ZengWen-DT <ceng.wen@xydigit.com>

---------

Co-authored-by: Cursor <cursoragent@cursor.com>
Co-authored-by: Peter Steinberger <steipete@gmail.com>
2026-07-17 19:02:43 +01:00
maweibin
b8c7f31894 fix(sessions): prevent delivery-mirror prompt contamination with adjacent dedup and identity fallback (#99470) (#99504)
* fix(sessions): prevent delivery-mirror prompt contamination with adjacent dedup and identity fallback (#99470)

Two-layer defence against delivery-mirror entries leaking into provider
prompts after session rebuild / side-branch merge strips metadata:

Layer 1 (identity fallback): isTranscriptOnlyOpenClawAssistantMessage
gains an openclawDeliveryMirror field check to catch stripped-metadata
survivors that lost provider/model during rebuild.

Layer 2 (adjacent dedup): normalizeAssistantReplayContent collapses
adjacent byte-identical no-tool-call assistant messages, catching
fully-bare {role,content,usage} survivors invisible to any metadata
filter.

P1 fix: added 'tool_use' (native Anthropic snake_case) to
TOOL_CALL_TYPES in extractToolCallsFromAssistant so adjacent dedup
never collapses tool-call-bearing turns.

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

* fix(sessions): narrow delivery mirror replay filtering

* test(sessions): preserve tool-call replay duplicates

---------

Co-authored-by: Claude Opus 4.8 <noreply@anthropic.com>
Co-authored-by: Peter Steinberger <steipete@gmail.com>
2026-07-16 15:19:49 -07:00
Alix-007
6bcf071120 fix(infra): bound macOS process start probes (#109064)
* fix(infra): bound macOS process start probes

* docs(changelog): note macOS process probe deadline

Co-authored-by: Alix-007 <li.long15@xydigit.com>

* test(infra): cover process probe timeout

---------

Co-authored-by: Peter Steinberger <steipete@gmail.com>
2026-07-16 11:36:07 -07:00
wuqxuan
e868a1dbd1 fix: recognize provider-wrapped HTTP status for session retry (#106850)
* fix: recognize provider-wrapped HTTP status for session retry

* fix(llm): scope wrapped status parsing to retry

Preserve the leading-status contract for rate-window and formatting callers while letting retry classification recognize built-in provider wrappers.

Co-authored-by: wuqingxuan <wu.qingxuan@xydigit.com>

---------

Co-authored-by: Peter Steinberger <steipete@gmail.com>
2026-07-16 00:40:15 -07:00
Peter Steinberger
4f40f46a08 docs(shared): clarify ignore anchoring 2026-07-14 12:19:39 -07:00
Peter Steinberger
a7f4e72216 test(shared): preserve tabbed ignore anchoring 2026-07-14 12:19:39 -07:00
Peter Steinberger
bfa72f8dab fix(shared): classify trailing-space ignore rules 2026-07-14 12:19:39 -07:00
Peter Steinberger
21515ae808 refactor(deps): reuse ignore matcher construction 2026-07-14 12:19:39 -07:00
moguangyu5-design
45395c2fd1 fix(shared): match nested gitignore semantics for unanchored patterns and escaped ! 2026-07-14 12:19:39 -07:00
Peter Steinberger
f81f9d8570 chore: enforce max-lines suppression ratchet (#107315)
* ci: enforce max-lines suppression ratchet

* chore: prune stale max-lines suppression

* fix: close max-lines ratchet enforcement gaps

* fix: harden max-lines ratchet checks

* fix(ci): satisfy max-lines ratchet checks

* style: format max-lines declarations

* fix(ci): match oxlint suppression grammar

* test: isolate max-lines git fixtures

* chore: prune resolved max-lines debt

* test: skip newline path fixture on Windows

* fix: harden max-lines suppression ratchet

* chore: refresh max-lines baseline

* fix: close max-lines ratchet bypasses

* fix: derive ratchet base from PR merge tree

* fix: support older Git in staged ratchet

* fix: align max-lines declarations and baseline

* chore: refresh max-lines baseline for current main

* fix: exclude generated wizard locales from max-lines

* chore: prune resolved max-lines debt
2026-07-14 09:27:02 -07:00
Peter Steinberger
8ea5ee2f17 refactor(terminal): unify bounded buffers (#107337)
* refactor(terminal): unify bounded buffers

* refactor(terminal): tighten buffer closure

* refactor(terminal): keep buffer policy private
2026-07-14 03:04:37 -07:00
snowzlmbot
e8ad0466ff fix: render assistant transcript headers safely (#99404)
* fix: render assistant transcript headers safely

Co-authored-by: snowzlmbot <293528334+snowzlmbot@users.noreply.github.com>

* fix(markdown): nest crossing annotation spans

* fix(markdown): protect final transport projections

* refactor(markdown): split transcript render ownership

* test(ui): cover assistant transcript render flag

* refactor(markdown): keep transcript helpers private

* docs(changelog): note assistant transcript headers

* chore(plugin-sdk): refresh transcript annotation baseline

* fix(markdown): harden final transcript projections

* docs(changelog): defer transcript note to release

* refactor(markdown): centralize HTML tokenization

* fix(markdown): satisfy lint gates

---------

Co-authored-by: Peter Steinberger <steipete@gmail.com>
Co-authored-by: snowzlmbot <293528334+snowzlmbot@users.noreply.github.com>
2026-07-14 02:25:37 -07:00
Peter Steinberger
b940339c32 fix: use plain agent progress labels (#107260)
* fix(channels): simplify agent progress labels

* chore: keep changelog release-owned

* chore: refresh bundled channel metadata
2026-07-14 01:00:24 -07:00
Peter Steinberger
b58a75d726 refactor(html): share entity decoding 2026-07-14 00:00:05 -07:00
Peter Steinberger
889b4f7dcf fix(control-ui): rotate branded progress labels (#107111)
* fix(control-ui): rotate branded progress labels

* chore: keep progress note in PR body
2026-07-13 21:42:35 -07:00
Peter Steinberger
0b96300fc6 refactor(shared): privatize internal helpers (#106868) 2026-07-13 15:40:31 -07:00
Vincent Koc
a8548a1191 refactor(shared): narrow entry status API (#106856) 2026-07-14 06:24:21 +08:00
Vincent Koc
d08228eee1 refactor(shared): privatize requirement helpers (#106837) 2026-07-14 05:50:55 +08:00
Peter Steinberger
2aa4ff0825 refactor: consolidate duplicate helper exports (#106016)
* refactor(normalization): consolidate string helpers

* refactor(normalization): consolidate agent ids

* refactor(paths): consolidate user path resolution

* refactor(gateway): preserve transcript helper facade

* fix(normalization): align helper build aliases

* fix(memory): keep helper import line neutral

* chore(plugin-sdk): align consolidated helper surface

* refactor(normalization): reuse lowercase string helper

* refactor(normalization): reuse record guard

* refactor(normalization): share surrogate boundary helper

* refactor(agents): share token estimate constant

* refactor(memory): distinguish standalone helper contracts

* refactor(normalization): share error cause formatter

* refactor(config): distinguish eligibility predicates

* refactor(plugins): share registry state symbol

* refactor(cli): reuse outbound dependency adapter

* refactor(cron): distinguish positive duration parser

* fix(gateway): keep transcript helper private

* fix(paths): preserve public helper status

* refactor(channels): reuse registry normalizer

* refactor(agents): reuse agent core runtime facade

* refactor(auth): reuse locked profile upsert

* refactor(records): distinguish trap-safe guard

* refactor(migrations): distinguish sync directory helper

* test(plugins): drop stale duration alias expectations

* fix(channels): remove stale registry import

* chore(plugin-sdk): refresh helper API baseline

* fix(memory): keep renamed helpers private

* fix(plugins): keep registry state key private

* fix(plugin-sdk): tighten wildcard surface budget

* chore(plugin-sdk): refresh rebased helper API baseline
2026-07-13 03:22:00 -07:00
Peter Steinberger
9ea4b167fa refactor(deadcode): trim channel auth exports (#106247) 2026-07-13 02:45:34 -07:00
Peter Steinberger
938d41014f feat(mobile): default pairing to full node access (#105928)
* feat(mobile): default pairing to full node access

* chore: leave release notes to release workflow

* refactor(mobile): bound pairing helpers

* chore(i18n): refresh mobile access inventory

* chore(ci): lower mobile pairing LOC baseline

* fix(mobile): complete pairing validation artifacts

* ci: remove stale transcript target export baseline

* fix(ios): wrap access upgrade guidance

* fix(ios): preserve localized access key

* fix(ci): dedupe read-only SQLite guardrail

* fix(mobile): secure full-access node setup
2026-07-13 02:30:45 -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
5cb074ece5 refactor: dedupe small async primitives (#105961)
* refactor(sqlite): remove unused async Kysely driver

Co-authored-by: Sarah Fortune <sarah.fortune@gmail.com>

* refactor(media): share promise memoization

* chore(sqlite): prune stale Kysely guardrails

* chore(media): lower runner LOC baseline

* style(shared): format promise memo tests

* chore(deadcode): refresh main export baseline

---------

Co-authored-by: Sarah Fortune <sarah.fortune@gmail.com>
2026-07-12 22:34:53 -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
55254c3a0b feat(nodes): route alerts to the active computer (#105083)
* 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
2026-07-12 10:05:50 +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
49b5b862ac feat: node-hosted plugins — dynamic tools, MCP servers, and skills (#90431)
* feat: node-hosted plugins — dynamic tools, MCP servers, and skills

Nodes become declarative plugin hosts:
- node.pluginTools.update: node hosts publish plugin-registered agent tool
  descriptors; gateway materializes them as agent tools executing via
  node.invoke under the node command allowlist, with tools.effective
  invalidation and node online/offline removal.
- Trusted paired-node descriptors: no gateway-side plugin registration
  required; gateway.nodes.pluginTools.enabled off-switch (default on);
  description/count caps; deterministic node-prefixed collision names.
- Declarative node-hosted MCP: nodeHost.mcp.servers (McpServerConfig shape)
  starts MCP clients on the node host, publishes tools as pluginId node-mcp,
  executes via built-in mcp.tools.call.v1 with per-layer timeouts, failure
  isolation, and orphan-safe shutdown. No re-pairing when servers change.
- Node-hosted skills: node.skills.update publishes ~/.openclaw/skills
  content (64 skills/64KB/512KB caps both sides); gateway merges them into
  the skills snapshot while connected and exec host=node is available, with
  node:// locators, node-prefixed collisions, disabled command dispatch,
  and gateway.nodes.skills.enabled + nodeHost.skills.enabled switches.
- Security: node-supplied pluginIds cannot satisfy pluginId-scoped tool
  allowlists unless gateway-registered; reserved node-mcp id requires the
  core MCP descriptor shape; protocol registry kept out of public
  plugin-sdk dts.
- E2E: pond harness proves publication, MCP round-trip, skills locator, and
  disconnect/reconnect for all three surfaces.

* style: format node-plugin-tools test

* fix(skills): keep status loader unfiltered when eligibility is passed

skills.status started passing eligibility for the node-skill merge, which
flipped loadWorkspaceSkillEntries into filtered mode and dropped disabled
skills from status reports (QA plugin-lifecycle-hot-reload timeout). Status
now merges node skills explicitly around an unfiltered load. Also: regen
docs_map for new node docs sections; add the intentional node-host MCP
onclose suppression to the lint-suppression allowlist.
2026-07-11 10:16:34 -07:00
xydt-tanshanshan
eb2f763674 fix(agents): add tool-activity heartbeat to keep subagent alive during tool calls (#95536)
* [AI] fix(agents): add run-scoped tool-activity heartbeat to prevent premature subagent idle timeout

Subagent LLM idle watchdog tripped during long-running tool calls because
tool completions did not reset the idle timer.

Implement a per-run tool-activity heartbeat:
1. notifyToolActivity(runId) — published from embedded-runner tool
   execution wrappers (attempt.ts) whenever a tool completes
2. onToolActivity(runId, listener) — consumed by streamWithIdleTimeout
   to reset the idle watchdog on tool completion
3. getLastToolActivityMs(runId) — shared timestamp Map so pre-stream
   activity is visible to armTimer before the first stream iteration
4. clearToolActivityRun(runId) — wired into the run lifecycle finally
   block to clean up listener sets and timestamps when the run exits

Scoped per-run via runId-keyed Maps to prevent concurrent runs from
resetting each other's idle watchdogs.

Related to #94124

* [AI] fix(agents): copy plugin/channel/before-tool-call metadata onto heartbeat tool wrappers

* [AI] test(agents): add metadata preservation regression tests for heartbeat tool wrapper

* [AI] fix(agents): preserve terminal presentation metadata on heartbeat tool wrapper

* [AI] chore: update test comment for four metadata copy calls

* fix: add periodic heartbeat during tool execution

Fire notifyToolActivity at tool start and every 60s via setInterval
so long-running tools survive the 120s LLM idle watchdog.

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

* fix: remove useless catch clause (no-useless-catch)

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

* fix: preserve Code Mode control-tool identity through heartbeat wrapper

Adds copyCodeModeControlToolIdentity() to replicate the WeakSet
membership that markCodeModeControlTool() sets. Without this,
the heartbeat wrapper drops Code Mode identity for exec/wait
tools, weakening before_tool_call policy and approval handling.

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

* fix: wrap deferred directory tools with heartbeat

resolveDeferredTool hydrates hidden catalog tools outside the
effectiveTools.map() wrapper, so they bypassed the periodic
notifyToolActivity heartbeat. Wrap the hydrated execute function
with the same start/interval/complete notification pattern.

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

---------

Co-authored-by: Claude <noreply@anthropic.com>
Co-authored-by: Vincent Koc <vincentkoc@ieee.org>
2026-07-11 17:50:33 +08:00
Peter Steinberger
7bf80dc2c6 chore(tooling): enforce formatting and refresh TypeScript checks (#104239)
* chore(tooling): enforce current formatter and refresh checks

* chore(tooling): keep release changelog formatter-owned

* chore(tooling): retain compatible Node type surface

* ci: enforce formatting for docs-only changes

* ci: isolate docs formatter check

* chore(tooling): apply updated lint and format rules

* chore(tooling): satisfy updated switch lint

* style(ui): apply Linux formatter layout

* test(doctor): match quiet local audio contribution

* test(doctor): assert quiet output only

* test(doctor): follow restored information contract
2026-07-11 01:09:51 -07:00
Peter Steinberger
f94a7dc183 feat(codex): supervise native Codex sessions (#104045)
* feat(codex): add native session supervision

* fix(codex): harden supervision integration

* fix(codex): preserve locked harness ownership

* fix(codex): fence native session archive

* fix(codex): revalidate archive binding ownership

* feat(codex): integrate supervision runtime

* feat(sessions): preserve harness-owned execution

* feat(sessions): persist harness ownership invariants

* feat(gateway): enforce harness-owned sessions

* feat(setup): enable detected Codex supervision

* feat(mac): expose supervised Codex sessions

* feat(ui): make Codex sessions actionable

* docs(codex): document session supervision

* test(codex): cover integration ownership

* chore(i18n): refresh supervision inventories

* fix(setup): finalize Codex activation atomically

* test(codex): narrow binding store update

* fix(sessions): preserve legacy model locks

* test(macos): serialize Codex catalog fixtures

* fix(sessions): preserve legacy lock admission

* chore(i18n): reconcile supervision metadata

* test(sessions): mark legacy lock fixture

* fix(macos): drain final Codex catalog frame

* docs: leave supervision note to release

* style(macos): satisfy Codex catalog type length

* chore: record session accessor seam owners

* fix(macos): honor configured Codex supervision

* fix(codex): preserve harness-owned model locks

* fix(codex): satisfy supervision lint gates

* chore(i18n): refresh native supervision inventory

* fix(codex): align supervision validation contracts

* fix(codex): close supervision boundary gaps

* fix(codex): preserve supervision activation contracts

* fix(codex): dispose standalone supervision runtime

* fix(codex): pin supervised source connection

* fix(plugins): bind delegated runs to exact session target

* fix(codex): scope supervised sessions to configured agents

* fix(codex): fingerprint effective supervision home

* fix(codex): normalize supervision plugin policy

* fix(codex): keep supervised bindings stable across upgrades

* fix(codex): guard all supervised binding connections

* fix(codex): preserve catalog filters and pending CAS identity

* fix(codex): preserve supervision identity for diagnostics

* fix(codex): bind uncertain commits to supervision connection

* fix(codex): satisfy supervision type boundaries

* fix(macos): reconcile current main validation

* fix(codex): handle absent runtime config in supervision

* fix(doctor): own local audio acceleration check

* fix(codex): satisfy integration lint gates

* fix(codex): satisfy lifecycle safety guards
2026-07-11 00:12:08 -07:00
qingminlong
4f1f7c6fb0 fix(nodes): resolve Unicode browser node names when configured by display name (#103548)
* fix-nodes-unicode-browser-node-names

* fix(nodes): preserve compact browser node selectors

* fix(nodes): normalize unicode node names canonically

* fix(nodes): scope compact browser selectors

* fix(nodes): preserve meaningful unicode marks

* chore: leave changelog updates to release automation

---------

Co-authored-by: Peter Steinberger <steipete@gmail.com>
2026-07-10 23:32:28 +01:00
Peter Steinberger
9b1c36d23c fix: prevent exec approval revocation races (#103515)
* fix(security): serialize exec approval mutations

* fix(security): preserve additive approval writes

* test(cli): expect normalized approval shape

* fix(security): preserve exec approval compatibility

* test(security): exercise locked approval initialization

* test(security): mock serialized approval helpers

* test(exec): derive enforced command path from plan

* fix(gateway): always return approval CAS conflicts

* fix(macos): serialize exec approvals writes

* fix(security): repair approval build errors

* fix(security): serialize exec approval mutations

* fix(security): fail closed on approval persistence errors

* test(security): cover detached approval persistence failures

* fix(security): harden exec approval state

* style(macos): format exec approval sources

* fix(security): complete exec approval hardening

Co-authored-by: Coy Geek <65363919+coygeek@users.noreply.github.com>

* fix(macos): preserve approved login-shell semantics

* fix(macos): keep login shell approvals one-shot

* fix(security): linearize exec authorization

Co-authored-by: Coy Geek <65363919+coygeek@users.noreply.github.com>

* fix(security): preserve durable approval basis

Co-authored-by: Coy Geek <65363919+coygeek@users.noreply.github.com>

* fix(security): bind exec grants to current policy

Co-authored-by: Coy Geek <65363919+coygeek@users.noreply.github.com>

* test(security): fix exec revocation fixtures

* test(security): align gateway approval fixtures

* fix(macos): return approval decisions

* chore(i18n): sync native approval strings

* test(security): align approval hardening fixtures

* test(node): authorize completed event fixture

* test(security): fix approval decision fixtures

* test(security): await durable approval visibility

* fix(exec): preserve concurrent approval grants

* fix(exec): address exact-head CI failures

* fix(exec): preserve concurrent approval promotions

* fix(exec): make Swift shutdown state explicit

* test(macos): handle approval read failures

* fix(macos): harden approval socket paths

* fix(macos): preserve exact shell payload bytes

* test(macos): make approval fixtures explicit

* test(macos): fix approval suite compilation

* fix(macos): bound approval socket JSONL reads

* chore: move exec approval note to release process

* chore: move exec approval note to release process

---------

Co-authored-by: Coy Geek <65363919+coygeek@users.noreply.github.com>
2026-07-10 21:35:05 +01:00
cavit99
5e250aac74 fix: A2A handoffs can duplicate message-tool replies (#97259)
* fix: stop A2A source-reply mirror duplicates

* fix(agents): harden A2A reply extraction

* fix(agents): preserve internal A2A source replies

* test(gateway): assert A2A mirror projection precisely

* test(agents): complete A2A payload fixtures

---------

Co-authored-by: Peter Steinberger <steipete@gmail.com>
2026-07-10 18:05:51 +01:00
Peter Steinberger
505f8ae6a3 fix(control-ui): harden workspace avatar projection (#103657)
* fix(control-ui): harden workspace avatar projection

Co-authored-by: LZY3538 <liu.zhenye@xydigit.com>

* refactor(gateway): remove dead avatar URL mapper

* test(control-ui): track avatar temp directories

---------

Co-authored-by: LZY3538 <liu.zhenye@xydigit.com>
2026-07-10 13:31:22 +01:00
Peter Steinberger
ecfea21eeb feat(webchat,cli): the lobster notices things (#103573)
The resident pauses its fidgeting and turns to watch passers cross the
ledge. After a droop it tidies up with a little broom. On lobster days
(shared day hash with the CLI banner cousin, now in src/shared) it wears
a sailor cap unless the seed already rolled headwear. The Dreams sleeper
half-opens one eye when pressed.
2026-07-10 10:25:08 +01:00
Ayaan Zaidi
04ff278a1d refactor(device-bootstrap): close bootstrap purpose type 2026-07-10 07:53:37 +05:30
Ayaan Zaidi
b7fa44abd3 feat(device-bootstrap): add control-ui bootstrap purpose 2026-07-10 07:53:37 +05:30