Commit Graph

79907 Commits

Author SHA1 Message Date
Peter Steinberger bf67e079a9 fix(ci): render only aggregate QA evidence (#124823) 2026-08-16 13:49:39 -07:00
ClawSweeper 92d0b826d6 fix(ui): make light-theme diff syntax readable (#124814)
Co-authored-by: RoboClaw <309084314+roboclaw-bot@users.noreply.github.com>
2026-08-16 13:47:54 -07:00
Peter Steinberger 0c6040eb14 fix(runners): align reclaim results with runtime (#124791)
* refactor(runners): prepare placement move targets

* fix(runners): preserve normalized dispatch targets

* style(protocol): format reclaim result type
2026-08-16 13:46:00 -07:00
Peter Steinberger 707d3f4adf refactor: split max-lines pilot files and retire suppressions (#124813) 2026-08-16 13:45:27 -07:00
Peter Steinberger 43483be28e perf(test): remove ClickClack scheduler waits (#124819) 2026-08-16 13:44:21 -07:00
Peter Steinberger 32f056f011 refactor(agents): persist directive facts at the assistant write boundary (#124793)
* refactor(agents): persist directive facts at the assistant write boundary

Assistant final text is now stripped of inline delivery directives once, at
the SessionManager append boundary, with the parsed facts persisted as a
typed openclawDelivery field on the assistant message (openclawDeliveryMirror
precedent, inside event_json — no schema change). Live session state is
replaced with the persisted canonical bytes so same-run continuations and
next-turn store rebuilds never diverge (prompt-cache invariant).

Delivery and restart recovery consume the stored facts instead of re-parsing
persisted text; pre-upgrade in-flight messages without facts intentionally get
no text-parse fallback (commented tradeoff at the read site). Directive
parsing is now code-region aware, so markers quoted in inline code or fences
neither parse nor strip — fixes the empty-code-pill display bug.

The undocumented reaction marker DSL ([[react:]], [[react_to_current:]]) is
deleted; structured message-tool reactions remain the canonical path. Stale
assertion-safety baseline entry removed with the parser.

Production net -10, tests net +38. Focused suites: 9,068 passed; pre-fix
regressions fail for the intended reasons. Codex autoreview clean.

* fix(agents): satisfy directive persistence gates

* fix(config): drop unused directive export

* fix(agents): preserve indented directive examples
2026-08-16 13:44:11 -07:00
Peter Steinberger a7433d92df fix(cli): restart disabled installed services (#124786) 2026-08-16 13:39:36 -07:00
Peter Steinberger 541f373bc0 refactor(validation): type producers and drop internal re-validation — pilot lane C (#124808) 2026-08-16 13:38:17 -07:00
Peter Steinberger 486b272e8c fix(ui): stop stale clients from acting connected (#124772)
* fix(ui): stop stale clients from acting connected

Carry reload metadata on terminal Control UI build rejections, render an explicit refresh-required recovery state, fence reconnect-only actions, and surface disconnected approval failures with accessible modal controls.

* fix(ui): preserve reconnecting session drafts

* fix(ui): preserve offline preference intent

* fix(ui): return owned fallback digest bytes

* test(ui): follow passive approval presentation

* fix(ui): distinguish stale builds from protocol mismatches

* style(ui): format gateway recovery phase
2026-08-16 13:38:09 -07:00
ClawSweeper 8277cb24a1 feat(tools): prompt proactive widget use (#124810) 2026-08-16 13:33:51 -07:00
Peter Steinberger 4312eb7ec5 fix(upgrade): retain owners in legacy cron stores (#124809)
Amp-Thread-ID: https://ampcode.com/threads/T-01a00a6a-b64e-74a5-8b15-2d3b966a468d

Co-authored-by: Amp <amp@ampcode.com>
2026-08-16 13:33:00 -07:00
Peter Steinberger 4bc37cd597 fix(state): copy-safe agent database registry via state-relative paths (schema v9) (#124728)
* fix(state): store in-root agent database registry paths relative to the state dir (schema v9)

Copied state directories retained stale absolute agent database registry rows. The combined gateway store then merged old and new copies, causing every sessions.list request to fail with SessionCanonicalKeyMigrationRequiredError.

Schema v9 stores in-root registry paths relative to the state directory; migration rewrites eligible rows, deletes stale duplicates, and preserves external paths.

* fix(voice-call): describe state-relative registry migration

* fix(state): preserve registry locator traversal

* test(macos): move PortGuardian schema-version boundary to v9

The store opens any state database up to maximumSupportedSchemaVersion,
which the schema v9 bump moved from 8 to 9. Shift the supported/newer
partition in the boundary test accordingly.

* fix(state): re-anchor copied default-layout registry rows instead of deleting them

Resolve the ClawSweeper P1 by preserving genuine external default-layout registrations, re-anchoring copied rows when an in-root counterpart exists, and deleting only dual default-layout conflicts.
2026-08-16 13:31:32 -07:00
Peter Steinberger 2523943ef1 feat(codex): name additional session-catalog homes (#124807) 2026-08-16 13:30:49 -07:00
Peter Steinberger 8b9650d42a fix(memory): fail corrupted index commands (#124770)
* fix(memory): fail corrupted index commands

* fix(memory): preserve promotion output limit

* fix(memory): keep ranked promotion output
2026-08-16 13:28:31 -07:00
Peter Steinberger 4d4ee7bc86 refactor(plugin-sdk): consolidate session catalog families (#124801) 2026-08-16 13:25:11 -07:00
Peter Steinberger df5b5baf83 fix(ci): invalidate extension boundary cache for attempt types (#124800) 2026-08-16 13:16:32 -07:00
Peter Steinberger bc24508f5e docs: correct code mode runtime contract (#124792)
Amp-Thread-ID: https://ampcode.com/threads/T-01a00b7c-b9f0-73d5-8fb7-e619e8e458e1

Co-authored-by: Amp <amp@ampcode.com>
2026-08-16 13:16:10 -07:00
Peter Steinberger de52a6c314 fix(ci): select aggregate QA evidence by manifest (#124802) 2026-08-16 13:14:49 -07:00
Peter Steinberger a0f4d5462a refactor(channels): carry typed approval-prompt bindings through signal/imessage send seams (#124742)
The Signal and iMessage channel plugins inferred approval prompts by
regex-sniffing rendered message text (header matching like 'Exec approval
required', /approve command parsing), violating the transport-only channel
doctrine: approval actions must stay typed until channel encoding.

The typed envelope already existed (channelData.execApproval with
approvalId/approvalKind/allowedDecisions) and every payload-level delivery
path consumed it; the regex paths were redundant re-derivation at the raw
send seam plus restart recovery for in-memory iMessage poll state.

- Signal: delete send-level prompt sniffing entirely; all approval sends
  already flow through typed structured-payload or native-handler paths.
- iMessage: sendMessageIMessage takes a typed approvalPrompt binding
  (id/kind/decisions) from the native approval handler instead of an
  approvalKind flag plus text re-parsing.
- iMessage poller: persist pending poll targets in the plugin keyed store
  so restart recovery no longer regex-scans chat history; typed recent-chat
  discovery for handle-only DM targets stays. Split poll-target ownership
  into approval-reaction-poll-targets.ts (max-lines).
- Plugin SDK: remove extractApprovalReactionPromptBinding — beta-only
  surface, never in a stable release, so no deprecation window applies;
  AGENTS.md now records that rule.

Accepted tradeoff: approval prompts delivered by a pre-upgrade process are
not rediscovered from chat text after restart (<=24h transient state;
persisted reaction bindings and event-driven tapbacks still work).
2026-08-16 12:57:34 -07:00
Peter Steinberger ed1799315e feat(ui): surface approvals passively and redesign the approval card (#124767)
* feat(ui): surface approvals passively and redesign the approval card

Approvals no longer auto-open the centered modal: the queue is reachable
only through the sidebar attention chip, while the owning session shows
the inline card and other sessions surface via the session-row shield
icon, agent badges, and the chip. Deletes the inline-vs-modal exclusion
machinery (modalApprovalQueue, inlineApprovalId, forceShowAll) and makes
modal dismissal close the view instead of denying the active request.

Card: severity now drives the accent color instead of a table row,
plugin/agent render as header chips, the session key moves behind a
collapsed Details disclosure (modal only), and low-value exec rows
(Resolved/Security/Ask) collapse into the same disclosure. The codex
app-server bridge stops duplicating the session key into description
text; the envelope already carries it.

* fix(ui): gate settings Escape on the approval dialog's recorded open state

ClawSweeper caught that shouldIgnoreSettingsEscape still inferred an open
approval dialog from queue non-emptiness; with passive approvals a pending
queue no longer implies a visible dialog, so settings would swallow Escape.
The exec-approval element now records dialogOpen as a fact and the guard
reads it.
2026-08-16 12:47:08 -07:00
Peter Steinberger d8ebe85c24 refactor(line): replace nine-marker prompt DSL with typed rich messages (#124755)
* refactor(line): replace nine-marker prompt DSL with typed rich messages

Delete the LINE plugin's double-bracket marker language (quick_replies,
location, confirm, buttons, media_player, event, agenda, device,
appletv_remote) and its parser. Portable interactions now flow through the
existing presentation-block seam (renderPresentation, matching Discord and
Feishu); LINE-specific cards ride closed channelData.line schemas mapped to
the existing Flex renderers. Prompt section shrinks to four capability
lines and explicitly de-fangs marker text. Removes the stale
assertion-safety baseline entry for the deleted parser.

Production LOC net -69, tests net -433. Suite: 510/510 green.

* fix(line): declare rich message schema dependency

* fix(line): satisfy rich message type checks

* docs(line): mark card fragments as partial
2026-08-16 12:45:39 -07:00
Peter Steinberger 4667d188f2 fix(codex): honor session node exec host (#124777) 2026-08-16 12:41:48 -07:00
Peter Steinberger d5db5854fe fix(cli): explain empty directory lookups (#124753)
* fix(cli): explain empty directory lookups instead of printing nothing

* fix(cli): distinguish unsupported self lookups
2026-08-16 12:39:36 -07:00
Peter Steinberger 09a76ac773 fix(gateway): preserve worker lifecycle failure reasons (#124774) 2026-08-16 12:35:06 -07:00
Peter Steinberger e40bd56dfd docs: remove agent-hierarchy guardrail from VISION roadmap
Agent-created agents (durable roster entries with provenance) are now
planned work, so the blanket VISION.md guardrail against agent-hierarchy
frameworks no longer reflects direction. The adjacent guardrail against
heavy duplicative orchestration layers stays.
2026-08-16 12:33:14 -07:00
Peter Steinberger 0d9b22ad2d fix(config): render actionable validation errors (#124763)
* fix(config): render actionable validation errors

* fix(config): cover service and gateway validation
2026-08-16 12:32:00 -07:00
Peter Steinberger 6cc72f9b3d fix: honor context caps on Codex-routed models (#124735)
* fix(codex): forward authored context caps

* test(codex): keep binding fixtures uncapped

* fix(agent-harness): separate authored context cap
2026-08-16 12:31:20 -07:00
Peter Steinberger 6abb1273bf fix(tasks): cancel subagents through gateway (#124752) 2026-08-16 12:31:15 -07:00
Peter Steinberger b1c2ed7d47 fix(openai): keep setup auth choices consistent (#124729)
* fix(openai): centralize setup auth metadata

* refactor(openai): overlay auth hooks in place
2026-08-16 12:31:02 -07:00
Peter Steinberger 91e537da15 fix(runners): preserve device sessions through lifecycle faults (#124744)
* test(runners): cover paired-node lifecycle wire

* fix(runners): preserve retryable device lifecycle

* test(runners): keep wire fixture internals local

* fix(runners): stop fallback on device capacity
2026-08-16 12:29:07 -07:00
Peter Steinberger 5d68a8e1db fix(config): preserve migration notice paths (#124719) 2026-08-16 12:27:09 -07:00
Peter Steinberger 29deb75ec5 refactor(gateway): drop dead session-subscriber registry surface (#124754)
* refactor(gateway): drop dead session-subscriber registry surface

getForConnection and both registry clear() methods had no production
callers — only server-chat-state.test.ts consumed them (verified by
repo-wide grep incl. plugin-sdk). The recency-sorted connToSessionKeys
index existed solely so getForConnection returned keys in subscription
order, an ordering nothing read, rebuilt via toSorted() on every
subscribe/unsubscribe/settle — including the provisional-replay settle
path.

unsubscribeAll now reads the reverse index directly from
connToSessionRecency's keys (same contents, no ordering), removing the
per-call O(k log k) rebuild and the duplicate map. Tests assert through
get()/getApprovals(), the production read paths, per test-audit norms.

Behavior-neutral: subscription state transitions and event-visible
delivery unchanged; chat-state, broadcast, node-subscription,
instance-runtime, agent-events, session-events suites pass.

* test(gateway): fix ETXTBSY flake in workspace-sync candidate bounding

The test rewrote its mock git script between two createGitTransferList
calls. On Linux CI the second spawn can race a lingering fork of the
first child still holding the script's write fd, failing exec with
ETXTBSY. Write the script once; vary the entry count through a data file
the script reads instead.
2026-08-16 12:26:32 -07:00
Peter Steinberger 820bcb78cd fix(outbound): record queue-write loss and fail every payload on prep abort (#124756)
* fix(outbound): record queue-write loss and fail every payload on prep abort

Two silent-observer gaps in the outbound queue admission path:

1. Best-effort staging/queue-write failures were swallowed with a bare
   'return null'. The send proceeded live-only, so a crash mid-send lost
   the message with zero forensic trace of why the write-ahead row was
   missing. Every sibling degradation on this boundary logs
   (persistQueuedPreSendState, the dispatch-refresh fallback); this one
   now warns with channel/target and the error.

2. Batch preparation failure emitted message_sent for only the first
   payload while audit emitted per-payload terminals, so plugins with
   message_sent hooks saw 1 failure for an N-payload batch. The failure
   path now emits one hook failure per logical payload, matching the
   audit terminals and the recovery sibling's
   queuedTerminalFailureEvents. The unused error.payload pick and its
   OutboundPayloadPreparationError import went with it.

Regressions: queue-write warn asserted in the existing best-effort
fallback test; new multi-payload prep-failure test asserts 2 hook
failures. Both fail pre-fix.

* chore(outbound): keep OutboundPayloadPreparationError module-local

Last external consumer went away with the per-payload emit; the
deadcode:exports gate rejects unused exports.
2026-08-16 12:21:26 -07:00
Eden 12138d2cee fix(line): retry lost pushes without duplicating an accepted send (#124464)
A LINE push made exactly one attempt, so a transient provider or transport
failure dropped the reply even though retrying was safe to do. Retrying alone
would have duplicated a send LINE already accepted, so every push now carries an
X-Line-Retry-Key and reuses it across attempts: LINE answers a replayed key with
409 and the accepted request's sent messages, which resolves to the original
delivery instead of a second message.

Retries follow LINE's documented policy - server errors and transport failures
only, never 2xx, 409 or any 4xx - and run through the shared channel API retry
runner in strict mode. Replies stay single-attempt because LINE offers no retry
key for them.
2026-08-16 15:21:20 -04:00
Peter Steinberger 75bcc5cebe fix(ui): keep Control UI device identity working on plain-HTTP origins (#124724)
* fix(ui): keep Control UI device identity working on plain-HTTP origins

@noble/ed25519 defaults its SHA-512 provider to crypto.subtle, which
browsers gate to secure contexts, so device identity silently vanished
on http:// LAN dashboards and connects fell back to shared-credential
auth with no pairing. Wire a lazy pure-JS @noble/hashes fallback for
SHA-512 and the fingerprint SHA-256, and drop the isSecureContext gate
in the connect path. Secure contexts keep the platform digests and pay
no startup bytes: the fallback loads as its own lazy chunk, kept out of
the gateway-runtime startup chunk on purpose.

* test(ui): cover device identity minting and signing without crypto.subtle

New jsdom regression suite fails on pre-fix code (subtle-less crypto stub
with getRandomValues, which real insecure contexts keep). Rewrites the
gateway connect tests that previously asserted the device-less insecure
fallback: an insecure context now attaches a device identity.

* docs(web): plain-HTTP dashboards now pair with a device identity

The signing key never crosses the wire, so HTTP+pairing is strictly
stronger than the old HTTP token-only fallback; HTTPS (Tailscale Serve)
stays the recommendation for transport privacy.

* fix(ui): drop unnecessary boolean literal compare in secure-context timing meta

* test(ui): declare device.id on the connect-frame test shape

* test(ui): split the subtle-less scope-upgrade e2e into the two real invariants

Without crypto.subtle the browser can now sign, so the banner offers the
explicit admin upgrade; manual-only guidance is reserved for browsers that
cannot mint an identity at all (no WebCrypto RNG). Also corrects the
connect-path comment: blocked storage yields an ephemeral identity, only a
failed mint degrades device-less.

* fix(ui): address review findings on the HTTP device-identity path

- Storage-blocked pages keep one stable in-memory identity per page
  lifetime instead of minting a fresh unpaired key on every reconnect,
  and a write-rejecting store no longer fails the mint (regression tests
  bite pre-fix).
- Connect timing now reports the real browser secure-context fact via a
  shared browserSecureContext() helper instead of inferring it from
  device-identity presence.
- Docs state the accepted trusted-proxy contract: browsers attach a
  device identity on every origin, so first connects follow the standard
  pairing flow (deviceAutoApprove or a one-time approval); device-less
  admission remains only for browsers that cannot mint an identity.

* refactor(ui): trim the connect-path additions under the max-lines cap
2026-08-16 12:20:00 -07:00
Peter Steinberger 22dd3d4ed0 fix(qa): preserve effective fast mode (#124762)
Amp-Thread-ID: https://ampcode.com/threads/T-01a00b6b-e4e9-74af-bb31-30363fae6c89

Co-authored-by: Amp <amp@ampcode.com>
2026-08-16 12:16:48 -07:00
WhatsSkiLL 08786d32b2 feat(codex): show sessions from additional homes (#124660)
* feat(codex): register additional session homes

* fix(codex): preserve automatic session homes

* docs(codex): explain automatic home discovery around sessionCatalog.homes

---------

Co-authored-by: IWhatsskill <284122573+IWhatsskill@users.noreply.github.com>
Co-authored-by: Peter Steinberger <steipete@gmail.com>
2026-08-16 12:14:10 -07:00
Peter Steinberger 34bfcdba58 fix(skills): report missing ClawHub skills as not found (#124764) 2026-08-16 12:13:20 -07:00
Peter Steinberger 7e92751d9a test(upgrade): drop retired agent context assertion (#124765)
Amp-Thread-ID: https://ampcode.com/threads/T-01a00a6a-b64e-74a5-8b15-2d3b966a468d

Co-authored-by: Amp <amp@ampcode.com>
2026-08-16 12:12:54 -07:00
Peter Steinberger ebe7af218c fix(cli): allow hook toggles to select an agent (#124761) 2026-08-16 12:11:44 -07:00
Peter Steinberger 6a0c9f43d2 fix(ci): keep QA evidence output repo-relative (#124760) 2026-08-16 12:08:48 -07:00
Peter Steinberger 6540028c79 fix(ci): snapshot synced Testbox candidates (#124743)
Co-authored-by: Amp <amp@ampcode.com>
2026-08-16 11:56:02 -07:00
Peter Steinberger 6c9eda0593 fix(agents): preserve restart-unsafe delivery evidence (#124737) 2026-08-16 11:53:44 -07:00
Peter Steinberger a741f5b8ae refactor(mcp): centralize tool filter policy (#124739) 2026-08-16 11:51:23 -07:00
Peter Steinberger a2067ed1bb fix(cli): forward agent name through setup (#124740)
Amp-Thread-ID: https://ampcode.com/threads/T-01a00b6b-e4e9-74af-bb31-30363fae6c89

Co-authored-by: Amp <amp@ampcode.com>
2026-08-16 11:51:16 -07:00
Peter Steinberger 5168b5d4ab feat(voice-call): sessionScope "main" routes calls into the agent main session (#124708)
* feat(voice-call): add sessionScope "main" for main-session call routing

Inbound and outbound calls can now share the configured agent's main
session instead of a dedicated voice session. The new scope resolves
through the existing explicit-key canonicalization path, honoring core
session.mainKey and global-scope aliasing. The inbound webhook path now
forwards coreSession like every other resolver call site.

* style: format events.test.ts

* test(voice-call): split events.test.ts under the max-lines cap
2026-08-16 11:47:47 -07:00
Peter Steinberger 568b920b21 feat(lint): enforce import ordering and deduplication (#124730)
* refactor(imports): dedupe and hoist imports

* feat(lint): enforce import/no-duplicates and import/first
2026-08-16 11:44:52 -07:00
Peter Steinberger cb8a7449e7 perf(test): reuse memory plugin module (#124741) 2026-08-16 11:41:08 -07:00
Peter Steinberger eb77ce5690 refactor(infra): split device pairing lifecycle modules (#124734) 2026-08-16 11:40:55 -07:00
Peter Steinberger 57ebd20566 fix(cli): fail absent service start and restart (#124711)
* fix(cli): fail uninstalled service mutations

Treat Gateway and Node start/restart as failures when no managed service is installed, while preserving absent-service stop as an idempotent success.

* docs(cli): clarify gateway restart recovery
2026-08-16 11:38:45 -07:00