Commit Graph

6309 Commits

Author SHA1 Message Date
Peter Steinberger
182be0f7c1 refactor(tests): deduplicate database-first guard fixtures (#117594) 2026-08-01 12:55:30 -07:00
Vincent Koc
6531ca91f4 fix(perf): separate warm and first-device health probes (#117525)
* fix(perf): separate warm and first-device health probes

* fix(perf): configure first-device health probe

* fix(perf): require connected health probes

* fix(perf): preserve generic health benchmark state
2026-08-02 03:30:17 +08:00
Vincent Koc
acf28495b1 fix(ci): repair plugin prerelease validation (#117562) 2026-08-02 03:29:21 +08:00
Peter Steinberger
bf99e43ee7 refactor: consolidate full release child workflows (#117385) 2026-08-01 12:14:23 -07:00
Vincent Koc
a164d9c477 chore: merge main into Docker portability fix
* origin/main: (26 commits)
  fix(update): return failure when dirty checkout blocks update (#117452)
  fix(auto-reply): apply mixed chat directives in one session transaction (#117542)
  refactor(ui): unify channel status and setup controls (#117499)
  fix(doctor): preserve surviving lint selections (#117543)
  fix(media): keep an unquoted MEDIA path with spaces as one media item (#112464)
  refactor(channels): consolidate lightweight plugin discovery (#117541)
  fix(imessage): prevent duplicate messages after delayed sends (#110853)
  refactor(memory): unify authoritative dreaming state and presentation (#117538)
  refactor(agents): consolidate main-session recovery ownership (#117383)
  fix(proxy-capture): make path-based session cleanup atomic (#98852)
  refactor(agents): consolidate compaction and context-engine ownership (#117482)
  fix(gateway): preserve Responses usage details (#117533)
  perf(gateway): skip empty session recovery stores (#117498)
  fix(ci): update canonical Kova performance pin (#117508)
  fix(system-agent): emit the wizard cancel hint once per message (#113731)
  refactor: dedupe secrets runtime snapshot fixtures (#117502)
  test(google): cover ready callback close precedence
  test(openai): dedupe realtime voice fixtures (#117503)
  fix(google): flush lazy prompts on provider readiness
  fix(gateway): keep canonical hooks on pristine startup path (#117493)
  ...
2026-08-02 02:20:18 +08:00
Vincent Koc
ace5d9ada7 fix(ci): update canonical Kova performance pin (#117508) 2026-08-02 01:28:23 +08:00
Vincent Koc
e3c16ac65c chore: merge main into Docker portability fix
* origin/main: (27 commits)
  fix(plugins): compare authoring metadata by canonical JSON semantics (#117486)
  fix(doctor): reject contradictory lint check selectors (#117495)
  fix(anthropic): honor configured model pricing (#117275)
  refactor(plugins): reuse scoped loader for capability discovery (#117373)
  refactor(test): derive changed tooling routes (#117407)
  fix(kova): clarify extension memory attribution (#117500)
  fix(imessage): sanitize private context on every outbound path (#117501)
  fix(ci): align release validation fixtures (#117494)
  fix(talk): preserve owner authorization in realtime consults (#114163)
  fix(ui): surface aborted-run diagnostics (#117497)
  perf(models): skip Ollama row runtime loading (#117465)
  fix(cli): report user profile command outcomes (#117466)
  fix(active-memory): detect Chinese recall intent in escalate mode (#117338) (#117419)
  fix(workboard): ignore caller-supplied archivedAt when creating a card (#116412)
  fix(models): avoid waiting on promotions before listing models (#117322)
  refactor(plugins): inherit shared package boundary settings (#117474)
  fix(systemd): parse all inline environment assignments (#117484)
  feat(web-fetch): add tools.web.fetch.headers for operator request headers (#115545)
  fix(qa): Slack progress lane misses successful delivery (#117391)
  refactor: deduplicate Codex prompt snapshot fixtures (#117476)
  ...
2026-08-02 01:01:00 +08:00
Vincent Koc
b38bcd93d7 fix(kova): clarify extension memory attribution (#117500) 2026-08-02 00:41:35 +08:00
Vincent Koc
263741b1f0 fix(ci): align release validation fixtures (#117494)
* fix(release): align beta 6 e2e fixtures

* fix(doctor): preserve missing state startup signal

* test(release): align beta e2e contracts

* test(agents): use canonical empty auth store

* test(agents): isolate prompt cooldown scheduling

* test(release): align main validation fixtures

* test(release): accept Code Mode plugin tool evidence

* fix(test): repair release validation checks

* test(cron): assert structured session targets
2026-08-02 00:39:36 +08:00
Omar Shahine
5db7e1c4ec fix(talk): preserve owner authorization in realtime consults (#114163)
* feat(talk): forward realtime consult sender auth

* docs(talk): clarify realtime sender auth contract

* ci: constrain oxlint on hosted runners

* ci: split oxlint core on hosted runners

---------

Co-authored-by: Omar Shahine <10343873+omarshahine@users.noreply.github.com>
2026-08-01 09:37:17 -07:00
Peter Steinberger
faaeebe208 refactor: deduplicate Codex prompt snapshot fixtures (#117476) 2026-08-01 09:02:43 -07:00
Vincent Koc
c61388a0e0 test(docker): make line count assertion portable 2026-08-02 00:01:30 +08:00
Vincent Koc
93d99bbb08 fix(release): allow beta validation child completion (#117463)
* fix(release): allow beta validation child completion

* test(release): align package timeout contract
2026-08-01 23:43:07 +08:00
Peter Steinberger
e7950d968b refactor(state): inline canonical database schemas at build (#117433) 2026-08-01 08:39:42 -07:00
Dallin Romney
f1f53f49b3 fix(release): accept legacy Codex follow-through delivery (#117458)
* fix(release): accept legacy Codex follow-through delivery

* docs(release): explain extended-stable Codex validation
2026-08-01 23:30:47 +08:00
Peter Steinberger
9e43844264 build: generate native Canvas resources on demand (#117424) 2026-08-01 08:16:56 -07:00
Peter Steinberger
6affe7cf54 fix: harden plugin import-boundary guards and remove dead scanner (#117386)
* fix: harden plugin import-boundary enforcement

* fix: exclude generated bundles from plugin source guards

* fix: make plugin boundary scanner linear and complete
2026-08-01 07:49:56 -07:00
Peter Steinberger
deabae48d3 fix(ci): keep PTY tests observable and wait for completed turns (#117405)
Co-authored-by: Peter Steinberger <steipete@macos.shared>
2026-08-01 07:46:46 -07:00
Peter Steinberger
385f1dee16 docs: generate docs map at publish time (#117398)
* docs: generate docs map at publish time

* fix: canonicalize Docker pack entry path

* fix: preserve package lifecycle ownership
2026-08-01 07:01:43 -07:00
Dallin Romney
40e1ce6dc3 fix(qa): satisfy update lane execution contracts (#117388) 2026-08-01 21:28:14 +08:00
Jacob Tomlinson
20ac22f647 fix(codex): guide recovery from unimported agent auth (#116807)
* fix(codex): diagnose unimported agent auth

Add agent-scoped Codex migration guidance and expose a validated --agent target so non-default credentials cannot be imported into the default agent store.

Fixes #116763

* fix(codex): surface auth migration before route planning

* fix(codex): scope auth migration recovery

* fix(codex): preserve API key auth fallback

* test: repair memory importer routing expectation

* test: drop superseded memory routing repair

* test(tui): report PTY progress verbosely

---------

Co-authored-by: fuller-stack-dev <263060202+fuller-stack-dev@users.noreply.github.com>
2026-08-01 07:08:02 -06:00
Dallin Romney
f5989ea1f6 fix(qa): start Telegram plugin in bot-token runtime (#117389) 2026-08-01 20:57:46 +08:00
Peter Steinberger
b5a59e0a7d refactor(docker): consolidate E2E scenario helpers (#117359)
* refactor(docker): consolidate E2E scenario helpers

* fix(ci): retain release harness entry

* test(docker): complete package helper fixture
2026-08-01 05:48:28 -07:00
Peter Steinberger
8738fe1354 refactor(codex): deduplicate generated protocol schemas (#117382) 2026-08-01 05:32:37 -07:00
Peter Steinberger
142ad75c43 refactor: compact database-first legacy store guard (#117347) 2026-08-01 05:07:21 -07:00
Peter Steinberger
cd4bd7c6c0 fix(tui): cancel buffered submissions on shutdown [AI-assisted] (#117331)
* fix(tui): cancel buffered submissions on shutdown

* refactor(tui): preserve callable submit coalescer

* test(tui): run local PTY smoke against built CLI
2026-08-01 05:00:05 -07:00
Vincent Koc
2d545c16c3 fix(ci): use corrected Kova release evaluator (#116920) 2026-08-01 19:44:38 +08:00
Dallin Romney
c81bb3958c fix(qa): lease credentials for Telegram startup proof (#116842)
* fix(qa): lease Telegram startup credentials

* refactor(qa): trim credential lease surface
2026-08-01 17:13:27 +08:00
Dallin Romney
6baf4dd15f fix(release): validate candidates before Docker publication (#117252)
* fix(release): validate candidates before Docker publication

* fix(release): complete Docker publication gates

* fix(release): serialize Docker publication
2026-08-01 16:08:49 +08:00
Vincent Koc
f5a8cb02ea test(release): repair full validation regressions (#116931)
* test(discord): mock thread delete listener

* test(qa): expect blocked update evidence

* test(telegram): preserve recovered context body

* fix(test): configure kitchen-sink personality

* test(browser): expect canonical staged upload paths

* test(browser): canonicalize macOS download roots

* test(feishu): seed legacy session rows offline

* test(telegram): isolate message context session stores

* test(qqbot): expect canonical media paths

* test(anthropic): match canonical transcript paths

* test(qa): expect canonical session store keys

* test(gateway): isolate rewind media reads

* test(release): review plugin child spawns

* test(plugins): expect process-stable manifest metadata

* test(google): retire usage telemetry contracts
2026-08-01 15:42:50 +08:00
Peter Steinberger
137050cedd perf(update): reuse dev preflight build cache (#117246) 2026-07-31 22:59:44 -07:00
xingzhou
1f40646f7e fix(board): prevent emoji corruption in event notices (#111702)
* fix(board): preserve Unicode notice boundaries

* test(board): document surrogate boundary

* test(pr): isolate wrapper command inventory
2026-07-31 22:57:11 -07:00
Peter Steinberger
ad409a8285 fix(ui): preserve session, tool, archive, and focus ownership (#117191)
* fix(ui): unify tool, session, and keyboard interaction owners

* refactor(ui): separate archived session regression coverage

* test(ui): isolate memory plugin mutation mock registries

---------

Co-authored-by: Peter Steinberger <steipete@macos.shared>
2026-07-31 22:45:53 -07:00
Vincent Koc
6922ddd936 fix(qa): isolate runner discovery facades (#117203) 2026-08-01 13:40:11 +08:00
Dallin Romney
bcff3a0de3 fix(qa): bind Codex auth fixture to runtime version (#116859)
* fix(qa): update Codex auth fixture protocol version

* test(qa): bind Codex auth fixture to runtime version

* test(qa): load Codex fixture version through public surface
2026-08-01 13:36:31 +08:00
Dallin Romney
947886e764 fix(qa): align release harness contracts (#116812) 2026-08-01 13:24:10 +08:00
Dallin Romney
8b1a9ccaa4 fix(voice-call): preserve tool invocation context (#116856)
* fix(voice-call): preserve tool invocation context

* fix(voice-call): trust requester tool context

* style(voice-call): format invocation context test
2026-08-01 13:23:24 +08:00
Dallin Romney
f9d2f0dc86 fix(qa): restore WebChat auto-TTS proof (#116810) 2026-08-01 12:28:43 +08:00
Spencer Fuller
3374f78ad8 fix(queue): prevent cron saturation from starving hook dispatch (#116666)
* feat(hooks): dispatch hook agent runs into a dedicated command lane

Hook agent runs passed lane:"cron", which resolveCronAgentLane remaps to
cron-nested — the same lane cron's own inner agent work uses, capped at the
hardcoded cron budget of 8. Eight busy cron turns therefore starved every hook.

Adds CommandLane.HookDispatch and dispatches hook runs into it. Neither lane
resolver needs changing: resolveCronAgentLane (agents/lanes.ts:15-22) and
resolveGlobalLane (embedded-agent-runner/lanes.ts:11-18) special-case only
"cron" and pass every other lane through.

This is lane identity only. It does NOT yet bound aggregate capacity — that is
the capacity group in the following commits. On its own this widens total
command-lane concurrency by the hook lane's width (1).

Consumers that inferred cron-ness from the lane, both preserved rather than
silently changed:
- heartbeat-runner-execution: HookDispatch added to the busy-lane check so hook
  work still suppresses heartbeats; only the lane it occupies changed.
- session-suspension: explicit resume concurrency and gateway-managed-lane
  membership, instead of falling through to the custom-lane default.

server-lanes publishes the lane at width 1: the guarantee is that a hook can
always start under cron saturation, not that hooks run concurrently.

Test: server.hooks-lane.test.ts asserts the dispatched lane and that it survives
cron lane resolution unremapped, with a positive control on the inputs that DO
remap. Mutation-verified — reverting the call site to "cron" fails it with
'expected cron to be hook-dispatch'. Nothing else in the suite reads the
dispatched lane, so without this assertion the change regresses silently.

Refs: openclaw#98813, openclaw#43235

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>

* feat(queue): capacity groups with hard per-member reservations

Adds optional capacity groups to the command queue: lanes in a group share one
hard aggregate budget, and a member may hold a non-borrowable reservation
within it. This is what makes a separate hook lane safe — it bounds hook and
cron-nested work together at the existing cron cap instead of adding a slot
outside it (openclaw#98813 maintainer audit measured cron-nested=8 + hook-a=1 +
hook-b=1 = 10).

Group capacity is always DERIVED from members' activeTaskIds, never a separate
counter. Timeout, abort, clear, reset and stale-generation completion therefore
release capacity for free, because they all remove the task id; the only
remaining obligation is that those paths re-drain the group.

- setCommandLaneGroup / clearCommandLaneGroup / drainCommandLaneGroup
- admission: lane max, then group budget, then sibling reservations. A member
  may burst above its own reservation only into unreserved capacity.
- both completion paths (success AND error) wake group siblings; freed capacity
  belongs to the group, so a lane-local pump would strand a queued sibling
  behind capacity that is already free. resetCommandLane likewise.
- membership lives in the queue singleton keyed by lane name, NOT in LaneState,
  so setCommandLaneConcurrency cannot detach a member from its group.
- deadlock guard: rejects cron/main/subagent/nested and session:*/nested:*/
  context-engine-turn-maintenance:* — lanes that can be synchronously awaited,
  where a group wait would become a deadlock.
- rejects sum(reservations) > budget rather than starving silently.
- snapshot exposes group/groupActive/groupBudget/reservedForLane/blockedBy.

Tests: 9 new, all mutation-verified — dropping group admission fails 5,
removing the sibling wake fails 2, making reservations borrowable fails 2
("expected 4 to be 3": an idle sibling's reserve being borrowed). 57 pass
across all command-queue suites.

Not yet wired: no group is configured by default. That, plus group-wait
visibility and atomic publish, are the following commits.

Refs: openclaw#98813, openclaw#43235

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>

* test(queue): blockedBy answers hypothetical immediate admission, not queue state

Round-4 review (costaff-lapclaw-001) named this as the precision requirement
that decides whether the wait-visibility fix is vacuous:

  noteLaneWaitIfBusy runs BEFORE enqueue, so it snapshots the lane with
  queuedCount === 0. If blockedBy were populated only for an already-queued
  head entry, that snapshot would read "not blocked", no
  onLaneWait(waiting:true) would fire, and agent-watchdog's setup-timeout
  suppression would never engage — a run merely waiting on group capacity
  would take a false setup timeout.

resolveLaneBlockReason already answers "could this lane start work right now?"
independent of queue contents; these tests pin that contract:

- 7 cron active, hook holding the group's reserved slot: cron reports
  sibling-reservation with queuedCount 0 and activeCount < maxConcurrent, while
  the hook reports null (so the assertion discriminates rather than being
  always-truthy).
- a member lane that was never enqueued or was retired while idle still reports
  its group block state, instead of the not-found path returning a bare default
  that reads as free.

Mutation-verified: gating blockedBy on queue.length > 0 fails 3 tests with
'expected null to be sibling-reservation' — the exact symptom predicted.

Refs: openclaw#98813

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>

* feat(queue): atomic lane publication, group-aware wait visibility, opt-in group

Closes the remaining two round-2 blockers and wires the default group.

publishLaneConfiguration({lanes, groups, clearGroups}) applies lane maxima and
group definitions as ONE transaction: install with dispatch suppressed, then a
single commit-time drain. The per-lane setter drains the instant a lane goes
positive and gateway publication was sequential, so a member could be widened
and dispatch BEFORE its group existed — admitting work above the budget the
group was meant to enforce. Validation throws before any drain, so a rejected
configuration cannot strand lanes widened and ungoverned.

lane-controller's noteLaneWaitIfBusy now also emits a wait when
snapshot.blockedBy != null. A group-blocked member has
activeCount < maxConcurrent and can have queuedCount === 0, so both lane-local
terms were false while the task genuinely could not start. This is not just
observability: agent-watchdog.ts suppresses the cron setup timeout only while
waitingForLane is true, so an invisible group wait produced a FALSE setup
timeout for cron-shaped runs.

The group is opt-in on hooks.enabled. The reservation is a real cost — it
withholds a slot from cron inner work even while the hook lane is idle — so it
is only paid where it buys something. This surfaced as a genuine regression:
server-lanes.test.ts asserts cron-nested alone reaches all 8, which an
unconditional group breaks. With hooks off, no group is installed, cron keeps
the entire budget, and such a deployment sees no behaviour change at all.
Turning hooks off on reload tears the group down (clearGroups).

With hooks ON, cron inner work trades one slot for the guarantee that hooks
cannot be starved. Aggregate stays exactly the pre-existing cron cap — no slot
added outside it, which is what openclaw#98813 was held for.

Tests: 6 new (3 publication, 3 opt-in), 135 passing across all affected suites.
Mutation-verified:
- sequential per-lane publication: 'expected 12 to be less than or equal to 8',
  the exact 8+4 additive leak, caught at PEAK not post-state as review required
- unconditional group: 'expected cron-hooks to be undefined'

Refs: openclaw#98813, openclaw#43235

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>

* test(queue): pin group-blocked lane waits to the setup-timeout suppression chain

Round-4 review (fiducian-spencer-001) asked for the 8-cron / hook-holding-
reserve / 8th-cron-waiting regression asserting no false setup timeout.

The chain spans three files:
  lane-controller.noteLaneWaitIfBusy -> onLaneWait({waiting:true})
  -> timer-job-runner.noteLaneState  -> watchdog.noteLaneWait()
  -> agent-watchdog:159-164          -> waitingForLane = true, clear timeout
  -> agent-watchdog:98               -> setup timeout suppressed

The watchdog end is already covered by agent-watchdog.test.ts. The link this
change introduced is the FIRST one, and it is the one that fails silently: a
group-blocked lane looks idle to a lane-local view, so no wait is reported and
a healthy run queued behind group capacity takes a false setup timeout.

The predicate was an inline closure, so it was untestable without the full
runner harness — and asserting a copy of it in a test would prove nothing.
Extracted as shouldNoteLaneWait(snapshot) and driven with real snapshots from a
real group:

- 7 cron active, hook holding the reserve: the test asserts explicitly that
  BOTH lane-local terms are false (activeCount 7 < maxConcurrent 8,
  queuedCount 0) and that the predicate still reports a wait.
- a hook blocked by a full group budget reports a wait.
- negative control: lanes that can start immediately report no wait, so a
  predicate hardcoded to true would fail.
- ordinary lane-local saturation still reports a wait (pre-existing behaviour).

Mutation-verified: reverting to the lane-local predicate fails 3 tests with
'expected false to be true'. 182 pass across all affected suites.

Refs: openclaw#98813

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>

* fix(queue): make rejected publication a no-op; always tear down the group on hooks-off

Round-5 implementation review (fiducian-spencer-001, CHANGES REQUESTED) found
one real atomicity bug and two test gaps. Both bugs are fixed and both are now
mutation-guarded.

BLOCKER — rejected publishLaneConfiguration left lane maxima mutated.
Phase 1 widened lanes, then setCommandLaneGroup could throw (e.g.
sum(reservations) > budget) with no rollback. No drain ran, so the old test's
activeCount === 0 assertion passed — but the lane sat at the new width governed
by NO group, and the next unrelated drain trigger would dispatch its preserved
queue ungoverned. The function comment promised exactly what the code did not
do. Validation is now a distinct phase 0 over every group spec before anything
is mutated; validateCommandLaneGroupSpec/installCommandLaneGroup split out so
setCommandLaneGroup and the transaction share one validation path.

BUG — hooks-off skipped group teardown when the grouped lane was suspended.
applyGatewayLaneConcurrency published only when the lane map was non-empty. With
hooks off, cron-nested is the only lane that can enter it, so a suspended
cron-nested left the map empty and clearGroups was never published. A previously
installed cron-hooks group survived, and the member resumed still paying a
reservation for a hook lane receiving no work. Now publishes whenever hooks are
disabled, regardless of the lane map.

Also (review item 4): a lane may now belong to at most one group.
installCommandLaneGroup removes it from any prior owner's members, which
otherwise kept counting its active tasks toward a budget it had left. Not
reachable with the single default group, but this is a public API.

Tests: 3 new. Mutation-verified —
- validating during install instead of before: 'expected 8 to be +0'
- restoring the non-empty-lane-map guard: 'expected cron-hooks to be undefined'
  (this one initially SURVIVED; the first version of the teardown test never
  simulated suspension, so it could not see the bug. Now seeds a cleared lane
  resume and publishes via the gatewayStart path.)
- hooks-off now proves it DRAINS the work its teardown releases, not just that
  membership was deleted.

Test teardown fixed: resetAllLanes preserves queued entries by design, so work
on a lane that never opened never settles. clearCommandLane rejects it instead.

Typecheck clean (tsgo core + core test, exit 0).

Refs: openclaw#98813

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>

* fix(queue): make setCommandLaneGroup self-waking; guard the clearGroups+invalid case

Round-5 implementation review from costaff-lapclaw-001 independently found the
same two bugs fiducian did (rejected-publish partial mutation, and hooks-off
teardown skipped when the grouped lane is suspended) — both already fixed in
0eb96a7. It raised two things fiducian did not:

1. The exported setCommandLaneGroup primitive was not self-waking. Replacing a
   group can FREE capacity — wider budget, dropped reservation, removed member —
   and queued members must not sit behind capacity that is already available.
   publishLaneConfiguration drains at commit, but the bare primitive is exported
   and its "replace" semantics silently stranded members until an unrelated
   poke. Now drains the union of previous and next members.

2. clearGroups combined with an invalid replacement was the worst case: the old
   group could be removed before the new one threw, leaving BOTH lane width and
   group membership partially committed. Phase 0 validation already ran before
   the clear after 0eb96a7, but nothing pinned it.

Also documents a limitation costaff noted: reservations are not validated
against the member's own maxConcurrent, because lane widths and group
definitions are published together and the width may not be applied yet at
validation time. A too-large reservation is accepted but partly unusable.

Tests: 2 new. Mutation-verified —
- removing the self-wake: 'expected 2 to be 5'
- validating during install instead of before the clear:
  'expected undefined to be cron-hooks' (the existing group torn down by a
  rejected replacement — costaff's exact worst case)

Reviewer agreement on the rest: admission arithmetic sound for the concrete
config, clearCommandLane correctly not wired (frees no active capacity), the
peak-occupancy publication test is the right shape, the static deadlock deny set
matches the known synchronous-wait lanes, and shouldNoteLaneWait's export is the
right trade over asserting a copied closure.

Typecheck clean (tsgo core + core test, exit 0).

Refs: openclaw#98813

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>

* style(queue): satisfy oxlint in the capacity-group tests

`check-lint` was failing on 21 errors across the four new suites:

- 17 `curly`: single-statement `for`/`for-of` bodies without braces.
- 4 `no-promise-executor-return`: `new Promise((resolve) => setTimeout(resolve, 0))`
  implicitly returns the Timeout handle from the executor. Rewritten to the
  braced form already used ~85 times elsewhere in the repo, e.g.
  `src/plugins/install-paths.test.ts:41`.

No behaviour change; the suites pass unchanged.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>

* refactor(queue): split capacity groups and shared state out of command-queue.ts

`check-lint` was failing `max-lines` on src/process/command-queue.ts: 918
counted lines against the repo cap of 700. The file was already only 51 lines
under the cap before this branch, so the new capacity-group code could not fit
in it.

Two pure moves, no logic change:

- `command-queue.state.ts` — the globalThis-backed queue singleton
  (`getQueueState`, same `Symbol.for` key), `normalizeLane`, and the
  `QueueEntry` / `LaneState` / `ActiveTaskWaiter` / `CommandLaneTaskMarker`
  types. Lets the group policy read lane state without importing the queue.
- `command-queue.capacity-groups.ts` — the group registry, eligibility policy,
  spec validation, install, and the block-reason computation.

The four near-identical "drain these member lanes" loops collapse into one
`drainMembers` helper. It keeps the load-bearing part of each original: the
lane is looked up rather than created, because `drainLane` goes through
`getLaneState` and would resurrect a scoped lane that
`retireIdleScopedCommandLane` had just removed. The one loop that additionally
tested `maxConcurrent > 0` loses that check, which was an optimisation only —
a zero-width lane's pump admits nothing.

The dependency on `drainLane` is passed in as a parameter rather than imported,
so the new modules stay acyclic; `setCommandLaneGroup`, `clearCommandLaneGroup`
and `drainCommandLaneGroup` remain exported from command-queue.ts as thin
wrappers, and every previously exported symbol is still exported from there.

command-queue.ts is now 676 counted lines; all three modules are under the cap.

Verified: `tsgo:core`, `tsgo:core:test`, `oxfmt --check`, `oxlint` all clean;
1007 tests across the 43 suites that touch command-queue pass.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>

* fix(queue): allow concurrent hook dispatch within cron budget

* test(gateway): prove hook burst concurrency stays bounded

* refactor(queue): keep capacity groups internal

* test(gateway): isolate steady-state hook admission

* fix(gateway): close hook lane on disable

* fix(gateway): retarget suspended hook resumes

* fix(gateway): restore hook group before lane resume

---------

Co-authored-by: Claude Opus 5 (1M context) <noreply@anthropic.com>
Co-authored-by: Vincent Koc <vincentkoc@ieee.org>
2026-08-01 11:49:16 +08:00
Peter Steinberger
45c2d5911a refactor(i18n): remove unused Apple contradiction report (#117182) 2026-07-31 20:36:52 -07:00
Sasan
6938f7dddb fix: allow gateway service commands for named profiles (#116314)
* fix: gateway service commands refuse a named profile or relocated OPENCLAW_HOME

- Resolve the default install identity against the canonical state directory
  for the active OpenClaw home and profile instead of the unprofiled OS
  account default.
- `--profile <name>` / `--dev` project `.openclaw-<profile>` state and config
  paths, so every named profile was classified as isolated state and refused
  `install`, `start`, `stop`, `restart`, `uninstall`, Doctor service repair,
  and self-update service handling.
- `OPENCLAW_HOME` relocates all OpenClaw path defaults and is documented for
  running as a dedicated service user; a relocated home is now an install
  identity. `HOME` alone still is not.
- An `OPENCLAW_STATE_DIR` or `OPENCLAW_CONFIG_PATH` pointing outside those
  canonical paths is still treated as isolated state.
- Recovery guidance in the refusal message now names the paths that must match.

Verified: focused vitest shards for the changed suites plus the daemon, CLI,
and doctor suites that consume the identity check; tsgo core and core-test
lanes; oxlint; docs format, MDX, link, and map checks.

* fix(gateway): keep relocated homes isolated

* fix(config): validate service profile identity

* fix(daemon): enforce named-profile service ownership

* fix(update): reject drifted service selectors before probes

* test(windows): prove scheduled task lifecycle

* test(windows): harden scheduled task proof cleanup

* test(windows): bind lifecycle proof to checkout

* test(windows): normalize cleanup exit status

* test(windows): verify effective task privilege

* test(windows): protect scheduled task proof roots

* test(windows): prove listener-owned task lifecycle

* test(windows): fix scheduled task proof contracts

* test(windows): remove redundant mock coercions

* test(windows): measure fallback before task probes

* test(windows): prove scheduled task process origin

* fix(gateway): preserve unmanaged restart fallback

* test(gateway): cover denied restart ownership

* test(gateway): keep restart helper types private

* test(gateway): classify lifecycle helpers as test code

---------

Co-authored-by: Vincent Koc <vincentkoc@ieee.org>
2026-08-01 11:28:39 +08:00
Peter Steinberger
7e78de747b refactor(ui): replace duplicated locale bundles with canonical translation memory (#117157)
* refactor(ui): generate locale bundles from canonical translation memory

* fix(ui): keep server-only locale config out of browser test helpers
2026-07-31 19:40:27 -07:00
Vincent Koc
89aadef6ef feat(plugins): externalize iMessage channel (#117101) 2026-08-01 08:01:18 +08:00
Peter Steinberger
2fcb47ad1e refactor(test): derive changed-test routes from canonical owners (#117099)
* refactor(test): derive changed-test routes from canonical owners

* fix(test): type workflow owner descriptors for lint
2026-07-31 16:40:46 -07:00
Peter Steinberger
433bb3f954 fix(cli): make commands, completion, and JSON output reliable (#116033)
* fix(cli): make commands, completion, and JSON output reliable

* fix(cli): reconcile completion coverage with current main

* test(cli): keep test routing stable across isolation lanes
2026-07-31 16:20:34 -07:00
Vincent Koc
61fb29e90a feat(plugins): externalize OpenCode Go provider (#117064) 2026-08-01 06:31:19 +08:00
Vincent Koc
a26f6c8374 fix(test): avoid macOS release gate deadlocks (#116972)
Fix macOS test harness deadlocks in workflow and release evidence fixtures.
2026-08-01 06:19:23 +08:00
Peter Steinberger
4976eb38ab fix(ui): honor Gateway readiness abort and subscription ownership (#117048)
* fix(ui): keep canceled gateway waits retired

* test(ui): bind Gateway readiness test helper callback

* test(ui): isolate server locale preference singleton

---------

Co-authored-by: Peter Steinberger <steipete@macos.shared>
2026-07-31 15:06:55 -07:00
Jason (Json)
ae27d79364 fix(updater): harden launchd replacement timing (#117030)
* fix(updater): harden launchd replacement timing

* fix(updater): recover failed launchd replacement
2026-07-31 16:02:00 -06:00
Peter Steinberger
21fba83254 fix: live updater no-op restarts healthy gateways (#117038)
* fix(updater): route managed health through overlay

* style: format live updater probe

* test: align live updater readiness types
2026-07-31 14:34:14 -07:00