Commit Graph

77 Commits

Author SHA1 Message Date
Colin Johnson
de9ed64c29 feat(talk): enable GPT Live with Codex OAuth (#113354) 2026-07-25 20:41:27 -04:00
Peter Steinberger
6277c35d9a fix(ui): restore one-of skill binary setup and installation (#113767)
Co-authored-by: Peter Steinberger <steipete@golden-gate.local>
2026-07-25 11:01:25 -07:00
Peter Steinberger
35ce322a6c fix: reconnect after browser gateway handshake errors (#113689)
Co-authored-by: Peter Steinberger <steipete@golden-gate.local>
2026-07-25 06:59:44 -07:00
Peter Steinberger
c519e01a24 feat(gateway): chat.send expectedLeafEntryId precondition keeps stale panes off switched branches (#113073) 2026-07-23 12:33:31 -07:00
Peter Steinberger
013b24dd6d feat(sessions): archive attribution (archivedBy) (#113116)
* feat(sessions): attribute archive transitions

* docs: add archive attribution report

* fix(sessions): restore alias layout after archive audit failure

* docs: update archive attribution report

* fix(sessions): isolate archive audit rollback

* docs: record final archive rollback design

* fix(sessions): make archive audit note best-effort

* docs: record best-effort archive audit policy

* chore: refresh native i18n baseline
2026-07-23 11:23:30 -07:00
Peter Steinberger
09672312c4 feat(gateway): incognito sessions for the web Control UI (#113006)
* feat(gateway): add web-only incognito sessions held in process memory

* feat(ui): add incognito toggle and badges to the web new-session flow

* fix(sessions): classify incognito by key shape, fail closed on stale keys, and gate memory writes

* fix(codex): start harness threads ephemeral for incognito sessions

* fix(sessions): reshape internal-effects incognito keys and add doctor repair for reserved key collisions

* refactor(plugin-sdk): export canonical incognito key classifier and guard the sentinel path

* fix(state): classify incognito DB handles from the recorded open-time set

* fix(gateway): isolate incognito sessions from durable lineage and allocation on read-only misses

* docs(sessions): pin the reserved incognito namespace ownership decision

* feat(gateway): admin-scope incognito visibility and incognito-blind cross-session surfaces

* fix(ci): repair kysely guardrails, dead export, docs map, protocol bindings, and ACP reset rotation

* fix(gateway): remove non-admin observability side channels for incognito sessions

* fix(gateway): enforce admin-scope incognito access and cover all parent-reference creation paths
2026-07-23 09:04:36 -07:00
Peter Steinberger
6251343384 feat(sessions): visibility states, membership, and server-enforced participation (#112787)
* feat(sessions): enforce visibility and membership

* feat(ui): add session sharing controls

* docs: add session sharing implementation report

* refactor(sessions): use canonical creator identity

* fix(sessions): adopt creator ownership contract

* docs: refresh session sharing rebase report

* docs: record final creator integration proof

* docs: record final main rebase

* chore: drop worktree report artifact

* fix(sessions): keep drafts owner-only

* fix(ui): preserve redacted session restrictions

* fix(sessions): preserve scoped sharing authorization

* fix(sessions): re-verify session instance inside sharing mutation queue

* test(sessions): cover stale sharing mutation

* fix(sessions): bind membership to session instance, gate absence blocking on sharing

* fix(sessions): preserve entry normalization on rebase

* fix(sessions): atomic visibility instance guard, reset visibility on recreate

* docs(ui): name the absence-heuristic tradeoff and link follow-up

* feat(protocol): expose session sharing row state

* docs: note generated creator identity type

* fix(sessions): bind member writes and visibility rollback to session instance

* fix(ui): discard stale-connection sharing loads; drop worktree scratch files

* fix(ui): block composer only on observed sharing state, never on list absence

* fix(gateway): authorize agent runs against the resolved session (close keyless bypass)

* chore(protocol): allowlist Control UI-only session.sharing event for mobile

* test(config): record session.sharing keys in common-tier snapshot

* refactor(sessions): unexport internal sharing helpers

* test(gateway): update sessions changed routing assertions

* fix(sessions): align sharing identity with created actor

* fix(sessions): align membership identities and storage keys

* fix(gateway): re-filter drafts against fresh sharing state in sessions.list

* fix(gateway): drafts stay owner+admin only in the sessions.list fresh filter

* fix(ui): re-export sharing protocol types for the Control UI

* fix(ui): keep SessionSharingRole internal to satisfy deadcode gate

* fix(gateway): read runtime config lazily in session-mutation authorization

authorizeSessionMutation ran on every gateway request but eagerly called
context.getRuntimeConfig() — a non-trivial config resolve — for methods that
are never session mutations. Read config only once a real session-mutation
target is resolved. Also register the four session sharing methods in the
2026.7 release-train inventory test.

* fix(gateway): share one config snapshot across session-mutation authorization

Group rename/delete discovery and the authorization loop were each resolving
runtime config separately after the lazy-read change. Memoize the resolve so
non-session requests still pay nothing, while any session mutation resolves
config at most once and both discovery and authorization use that single
snapshot (no double reload, no mid-request config-change split).

* fix(gateway): resolve session-sharing CI gates

- isGatewayAdmin: null-safe connect access so internal/plugin-runtime runs
  (which reach authorization with a connect-less client) do not crash.
- emitSessionsChanged: scope only to a concrete session key; a [undefined]
  sessionKeys scope filters nothing correctly and would strip draft gating.
- session stores: mark the sync TOCTOU re-read and the sqlite_master
  existence probe as narrowly-justified raw SQLite primitives.
- tests: provide getRuntimeConfig to the session-action contract context,
  drop a shadowed 'call' binding, use structuredClone, and assert the
  agent-scoped sessions.changed broadcast shape.

* docs(gateway): note best-effort participation gate + refresh native i18n baseline

Session ownership/visibility are usability features, not a security boundary
(docs/concepts/multi-user.md, SECURITY.md); document that the pre-dispatch
authorization is intentionally not commit-bound to the resolved instance.
Also refresh apps/.i18n/native-source.json after the session-sharing protocol
codegen shifted line numbers of existing native strings (position-only).

* test(gateway): reset session sharing snapshots

* style(gateway): format sharing reset import
2026-07-23 08:53:57 -04:00
Peter Steinberger
6b470b1fe8 fix(ui): thread-changes button leads to a dead end when the workspace is not a git checkout (#112914)
* fix(ui): disable the thread-changes button when the workspace is not a git checkout

* chore(protocol): regenerate Swift gateway models for sessions.files.list gitCheckout
2026-07-23 01:33:35 -04:00
Peter Steinberger
099d6351b3 refactor(sessions): canonical lineage model — creation provenance, fork ancestry, generation chain, typed row contract (#111861)
* fix(sessions): preserve spawn/fork lineage across implicit daily/idle rollover

* refactor(sessions): canonical creation model with forkSource ancestry and generation chain

* feat(sessions): stamp creation provenance across all creation paths and emit created events

* refactor(gateway): lock lineage patching, split control from navigation, add typed session-row contract

* docs(gateway): document creation provenance stamping and lineage patch tightening

* fix(sessions): keep provenance proof-only on wire fallbacks and strip node-local lineage from cron continuations

* fix(gateway): never journal a created event for session adoption

* fix(gateway): keep post-create work on adoption while gating the created event

* fix(sessions): restore trusted ensure-main provenance and stamp navigation parent at spawn

* fix(sessions): allow parentSessionKey through the direct child spawn patch

* fix(ci): break type cycles, satisfy export scan, regenerate Swift protocol models

* refactor(sessions): replace createdBy with createdActor

* fix(protocol): export session row type

* fix(sessions): preserve proven creation provenance

* fix(sessions): close lineage creation gaps

* test(sessions): align atomic spawn lineage coverage

* test(sessions): widen transcript search reconcile wait

* fix(sessions): stamp reset-created rows

* test(sessions): keep reset provenance coverage focused

* fix(sessions): journal chat-created rows

* test(ci): anchor release skill reads to repo

* test(ci): avoid cached module paths
2026-07-22 22:54:31 -04:00
Peter Steinberger
cf2f591161 feat(sessions): permanent creator attribution, owner avatars, person filter, multi-user docs (#112658)
* feat(sessions): persist creator attribution

* feat(ui): add session creator filtering

* chore(sessions): refresh sqlite schema baseline

* docs(security): explain shared-agent trust

* fix(sessions): project catalog creator ownership

* fix(ui): restore startup JS budget headroom for creator attribution
2026-07-22 05:47:21 -07:00
Peter Steinberger
0c99a4e362 feat(ui): manage DM pairing requests in Channels (#112401)
* feat(ui): manage DM pairing requests

* fix(ui): clear pairing data across auth changes

* test(ui): tighten pairing page fixture type

* fix(gateway): complete pairing protocol contracts

* fix(ui): guard pairing mutations across epochs

* fix(ui): restore chat teardown gates

* fix(ui): isolate channel auth lifecycles

* fix(ui): remove stale chat view export
2026-07-22 04:54:20 -07:00
Peter Steinberger
0f066eec81 feat(dashboard): plugin widget kinds — native WorkBoard card and mini-board widgets (#112434)
* feat(board): add plugin widget kinds

* feat(ui): render native Workboard widgets

* fix(dashboard): compose plugin widgets with current main

* chore: internalize widget-kind contribution types

* fix(ui): retry plugin widget renderer loads

* fix(ui): harden Workboard widget refresh lifecycle

* fix(ci): clear plugin widget landing gates

* fix(boards): migrate plugin widget storage

* fix(db): migrate unreleased board widget constraint

* fix(ui): retry failed Workboard widget loads

* fix(ui): keep stale widget refresh cleanup inert

* fix(ci): align plugin widget landing guards
2026-07-21 17:59:20 -07:00
Peter Steinberger
1f0a3ecc68 feat(ui): session observer HUD, sidebar subtitles, and settings (#112260)
* feat(ui): session observer HUD, subtitle integration, and settings

* test(ui): observer demo fixtures for the mock control-ui harness

* fix(ui): satisfy lint and deadcode gates for observer surfaces

* test(ui): adopt renamed pull-request summary api after rebase

* fix(ui): clean rebase artifacts in observer test files
2026-07-21 17:05:14 -07:00
Peter Steinberger
98742bc2c7 feat(cron): stream schedule sources with durable source identity (#112387)
* feat(cron): stream schedule sources (supervised command stdout)

Add gated argv stream schedules with bounded line batching and trigger.streamBatch composition.

Reuse the gateway ProcessSupervisor for source ownership, deterministic teardown, capped restart backoff, and schedule-key guarded batch execution. Expose additive protocol, CLI, tool, UI, docs, and generated snapshot surfaces without storage DDL.

Contract: stream schedules are event-driven, require cron.triggers.enabled, reject command payloads, and retain at most one bounded pending batch.

* fix(cron): reject retired stream source epochs at run admission

Thread an invalidatable per-owner source-generation token (ownerNonce.generation)
through cron.run admission alongside the schedule key. A batch handed to cron.run
under one source epoch can wait behind another run while its owner is stopped; a
disable→re-enable or A→B→A edit leaves the schedule key unchanged, so the key
check alone would admit the retired epoch's batch. The token is persisted in
job.state on every lifecycle write and compared at every admission site plus the
executeJobCore guard, so a stale epoch's batch is skipped.

Also fix direct stream-job mutations recording the wrong lifecycle status when
global cron is off but triggers are on: extract resolveStreamStopReason so the
direct path reports the remediable cron-disabled state like reconcile does.

* fix(cron): close stream admission windows from round-10 review

- Persist the retired source generation before draining stop teardown, so a
  batch queued behind another cron run cannot gain admission during the up-to-10s
  in-flight-batch wait (server-cron routed stop path).
- Add streamSourceGeneration to the closed gateway response schema (excluded from
  the writable patch schema) so a running stream job passes strict result
  validation without letting callers spoof source identity.
- Close the mutation-epoch ABA: track an eviction epoch so a snapshotted absent-0
  is trusted as unchanged only when no LRU eviction happened during the await.

* refactor(cron): stream sources own a durable logical identity

Split the conflated restart-generation/admission token into two concepts:
a persisted streamSourceIdentity owned by cron store mutations (rotates on
enable/disable, source replacement, once-trigger auto-disable, and explicit
retirement; stable across supervised child restarts) and a watcher-local
process generation used only to fence stale child callbacks. Admission now
requires schedule key + identity together at every window, closing the
A-to-B-to-A and restart-flush races from review rounds 8-11.

Also: match-mode regexes now see raw source text (the [truncated] marker is
applied after matching), stop-timeout failures set the live restartExhausted
mirror so shutdown preserves the terminal diagnostic, and the watcher is
split into owner/output/registry modules under the max-lines budget.

* fix(cron): harden stream teardown and intake from round-4 review

An exit queued ahead of a requested stop no longer counts toward restart
exhaustion (the synchronous stop fence owns it), overlapping cron.stop and
stopAndDrain share one memoized shutdown drain instead of double-stopping
every owner, raw output intake is bounded at 4x the batch cap so normal
64 KiB pipe reads stop losing complete lines to OS chunk boundaries, and
persisted-shape quarantine coverage for unsafe match expressions is pinned.

* fix(cron): keep watcher-internal owner disposal from retiring live identity

Disposing an obsolete owner while a start replaces it is not a durable
removal; a retiring stop there rotated the live job's identity and stranded
the replacement behind the CAS ownership guard. Also align the docs with the
implemented match semantics: complete lines match on full text past the
batch cap, only intake-cut prefixes are unmatchable.

* fix(cron): make oversized-line matching independent of pipe chunking

Partial lines are retained up to the raw-intake bound rather than the
delivery cap, so a complete over-cap line matches identically whether it
arrives in one callback or several; only a line the intake bound itself cut
remains an unprovable prefix. Reconcile also contains schedule-replacement
stop failures per job, matching the other stop branches.

* fix(cron): bound assembled lines, drop stale payload override, barrier stopAll

- enforce the 4x raw-intake per-line cap while assembling split callbacks,
  so an oversized line stays an unprovable prefix regardless of chunking
- stop passing the watcher-cached payload as a cron.run override; the run
  snapshots the persisted payload under its admission lock
- stopAll waits for every owner stop to settle before surfacing failures
- split cron-stream-output interleaving tests into their own file (max-lines)

* fix(cron): address first full-CI round (lint, knip, schema test, unused param)

* chore(cron): refresh codex prompt snapshots for stream schedule schema

* fix(cron): keep the first clean line after an intake drop ending at a newline

* fix(cron): fence stream reconcile list snapshots against direct mutation routes

A cron.list snapshot captured across the reconcile await could be applied
after a direct add/update route already started the owner, stopping it as
removed and retiring its live identity. A mutation revision bumped at every
direct route start invalidates the stale snapshot; reconcile re-lists
(bounded) instead of applying it.

* style(cron): format stream owner imports

* fix(cron): discard severed stream prefixes at EOF

* fix(cron): retry failed stream shutdown drains

* fix(cron): honor stream stop fence after output drain

* chore(cron): refresh landing checks
2026-07-21 15:01:30 -07:00
Peter Steinberger
3a1351a303 fix(cron): show script automations across user clients (#112195)
* fix(cron): preserve script jobs across clients

* chore(i18n): refresh native cron strings

* chore(i18n): align rebased native catalogs

* chore(i18n): defer generated locale refresh
2026-07-21 08:02:59 -07:00
Peter Steinberger
49ff6a4497 fix(protocol): classify system agents in rosters (#111920)
* fix(protocol): classify system agents in rosters

* fix(ci): align agent kind client gates

* fix(ci): keep roster filtering in startup bundle

* chore(ui): remove superseded roster module

* style(android): satisfy agent kind test formatting

* style(linux): format merged agent capability assertion

* fix(config): reject reserved system agent ids

* chore(i18n): refresh native source inventory

* style(android): format agent kind surfaces

* fix(gateway): preserve configured agent ownership
2026-07-20 16:57:04 -07:00
Peter Steinberger
bc76bb8933 feat(agents): agent-controlled session status, attention, and TTL in the sessions tool (#111583)
* feat(agents): agent-controlled session status, attention, and TTL in the sessions tool

* feat(protocol): sessions.patch agent status fields and curated attention icon ids

* chore(protocol): regenerate bindings for agent-status patch fields, unexport internal cap

* chore(sessions): unexport internal agent-status TTL default
2026-07-19 21:01:09 -07:00
Peter Steinberger
3247a56d15 fix(ui): prevent cross-file mock leakage in Control UI tests (#111554)
* test(ui): stop shared mock registry leakage

* ci: add three-worker UI leakage canary
2026-07-19 15:38:50 -07:00
Peter Steinberger
6add21bf40 fix(ui): remove duplicate instanceId getter left by concurrent merges 2026-07-19 03:20:46 -07:00
Peter Steinberger
5c9916950e feat(gateway): watched sessions in presence with viewer facepiles (#111225)
* feat(gateway): expose watched sessions in presence

* fix(gateway): resolve concurrent watched-session rollbacks via in-flight state

* fix(ui): viewing CI conformance — lazy facepile, bindings, dead exports

* fix(ui): move viewer presence projection out of the startup chunk

* fix(ui): capture sessionKey before facepile filter closure
2026-07-19 02:53:19 -07:00
Peter Steinberger
ba06fe1541 feat(ui): author avatar chips on user messages (incl. queued) (#111309)
* feat(ui): author avatar chips on user messages with gravatar and initials fallback

Renders a small author avatar on user-authored chat messages, including
queued/pending sends, so multi-user gateways show at a glance who wrote
which prompt. Resolution: profile avatar URL (when available) -> Gravatar
by SHA-256 email hash (d=404) -> deterministic initials with stable color.
Assistant/tool output stays unmarked, and messages without sender identity
render unchanged, keeping single-user gateways visually identical.

* fix(ui): clear avatar fallback state on image load; document gravatar tradeoff

* fix(ui): gate email-hash avatars behind a gateway proxy base URL

Without a same-origin proxy base the email tier is disabled outright, so
rendering a transcript can never disclose hashed sender emails or viewer
IPs to a third-party avatar host. The gateway-side proxy route (follow-up)
supplies the base and becomes the only avatar fetch path.

* fix(ui): restrict profile avatar URLs to same-origin relative paths

* fix(ui): validate profile avatar URLs with the URL parser, not string prefixes

Backslashes normalize to slashes and tabs/newlines are stripped by browser
URL parsing, so startsWith checks can be bypassed into cross-origin fetches.
Resolving against a probe origin and requiring the origin to survive is
parser-equivalent and closes the class.
2026-07-19 02:08:05 -07:00
Peter Steinberger
918f6615d0 feat(ui): Swarm progress widget — dot grid per swarm group (#110325) (#111297)
* feat(ui): Swarm progress widget — dot grid per swarm group (#110325)

* fix(ui): keep swarm renderer internals private
2026-07-19 01:19:56 -07:00
Peter Steinberger
6c2973dee4 feat(ui): automatic session attention states in the sidebar (#111035)
* feat(ui): automatic session attention states in the sidebar (question, approval, failed run)

* test(ui): split attention presentation and read-marker cases under line budgets

* fix(ui): restore precise chat-pane test-support signatures
2026-07-18 17:43:59 -07:00
Peter Steinberger
5fdb0cd24e feat(chat): switch between session transcript branches from the chat header (#110857)
* feat(chat): switch between session transcript branches from the chat header

* fix(chat): type fixes and protocol regen for branch switcher CI
2026-07-18 20:06:36 +01:00
Peter Steinberger
88e5af7097 feat(ui): interleaved sidebar zone with custom session icons and drag ordering (#110682)
* feat(ui): custom session icons with agent-drawable SVG and nav-parity pinned rows

* wip: slice-2 interleaved sidebar zone (pre-review)

* fix(ui): trim icon exports, bypass protocol barrel in startup bundle, regen Swift protocol client

* fix(ui): preserve unknown-agent zone entries on writes, prune entries on any unpin

* fix(ui): reset keeps unloaded session slots; enforce SVG byte cap on canonical form

* fix(ui): archiving a pinned session retires its sidebar zone slot

* fix(ui): persist drag-pinned zone slot only after the pin patch lands

* fix(ui): recompute drop insertion against freshest zone order on pin ack

* fix(ui): consume self-drop events before the zone bailout

* docs(ui): note the non-sidebar unpin pruning contract on pruneSidebarSessionEntry

* refactor(ui): extract pure session-tree projection; drop unused zone type export
2026-07-18 17:13:09 +01:00
Peter Steinberger
0acece4591 feat(chat): rewind and fork a session from a message bubble (#110660)
* feat(chat): rewind and fork a session from a message bubble

* docs(web): document chat rewind and fork bubble actions

* fix(chat): lint cleanups, protocol regen, and test splits for rewind/fork CI

* fix(ui): fit chat rewind disabled styles inside the startup CSS budget
2026-07-18 14:46:34 +01:00
Alix-007
deccdb5e57 fix(ui): bound browser gateway WebSocket opening (#109037)
* fix(ui): bound browser gateway socket opening

* fix(ui): use browser-safe timeout export
2026-07-18 09:38:37 +01:00
Peter Steinberger
da44d52ac6 feat: ask_user — structured questions from the agent with web card, channel buttons, and text answers (#109922)
* feat(gateway): add transient question runtime (question.* methods + broadcasts)

* feat(agents): add blocking ask_user question tool with chat prompt delivery and text-reply claim

* feat(ui): interactive in-thread question cards for ask_user

* feat(channels): native tap-to-answer buttons for ask_user on Telegram, Discord, and Slack

* feat(ui): unify codex and gateway question cards with interactive gateway answering

* refactor(agents): collapse ask_user pending state to one registry; docs for ask_user

* fix(agents): include ask_user in normal gateway runs; add question-flow control-ui e2e

* test(ui): avoid credential-shaped fixture in question card test

* refactor(ui): reorder stream-group context keys

* fix(gateway,ui): validate question answers at resolve; reject secret/duplicate-label questions; UI retry and reconnect hardening

* fix(gateway,agents): canonicalize accepted option answers; bound ask_user option labels to 64 chars

* chore(ci): prune unused question exports, allowlist mobile question events, fix discord lint

* chore(ci): regenerate protocol/i18n/docs/tool-display artifacts for question surface

* fix(protocol): flatten QuestionRecord for native codegen; drop TS-only alias from schema registry

* chore(android): regenerate ask-user localization resources

* docs: regenerate docs map after rebase

* fix(ci): avoid stale read-only dependency disks

* test: remove stale reef lint suppression ratchet

* fix(ci): keep source locale drift advisory in release gates

* fix(ci): scope locale advisory handling to parity check
2026-07-17 22:24:17 +01:00
Peter Steinberger
61bec3a2de fix(ui): follow Gateway queue mode for active-run messages (#109441)
* fix(ui): inherit Gateway queue mode for follow-ups

* fix(ui): honor session queue overrides

* fix(ui): preserve Gateway follow-up semantics

* fix(ui): retain pane queue mode ownership

* fix(ui): keep Gateway queue policy authoritative

* chore(ui): leave locale refresh to workflow

* fix(ui): keep unresolved follow-ups neutral

* refactor(ui): isolate session queue projection
2026-07-16 20:59:11 -07:00
Peter Steinberger
00a6ecb906 feat(ui): always-on chat title bar with inline rename and workspace actions (#109422)
* feat(gateway): add sessions.files.reveal to open a session workspace on the gateway host

Resolves the session's workspace root server-side (same resolution as
sessions.files.list), refuses exec-node and cloud-worker placements, and
opens the directory with the platform opener. The opener helpers move out
of config.ts into a shared open-path module that config.openFile now uses.

* feat(ui): always-on chat title bar with inline rename and workspace menu

Every chat pane now renders its header: click the session title to rename
it inline (Enter commits via sessions.patch, Escape cancels), a workspace
chip names the session's checkout with reveal/copy-path/copy-branch
actions, and cloud-worker sessions show a globe. The single-pane floating
toggle cluster and the transcript's reserved titlebar drag band fold into
the header, which keeps native macOS window dragging.

* fix(ui): resolve title-bar session aliases and clear the collapsed-nav overlay

Live verification found two gaps: route aliases like ?session=main showed
the generic key-derived title instead of the session's label (resolve via
hello defaults + key equivalence, matching the pane), and the floating
sidebar-expand pill overlapped the header title on plain web while the nav
was collapsed (52px inset, mirroring the native-shell clearances).

* fix(ui): keep the protocol schema layer out of the Control UI startup bundle

The title-bar change made session-row-badges runtime-import the
gateway-protocol barrel for one classifier, dragging typebox and every
schema into startup JS (395 KiB gzip vs the 370 KiB budget). The placement
vocabulary now lives in a dependency-free session-placement-state module:
the schema union derives from it, the barrel re-exports it, and the UI
deep-imports it (startup back to 361.8 KiB).

* fix(gateway-protocol): keep SessionPlacementStateSchema statically typed

Type.Union over a mapped array loses tuple inference and collapses Static
to never; the literal list stays explicit with a compile-time guard tying
it to the shared SESSION_PLACEMENT_STATES vocabulary.

* chore(protocol): regenerate Swift/Kotlin bindings for sessions.files.reveal

* chore: narrow new exports flagged by the deadcode gate

* chore(i18n): leave generated locale artifacts to the locale-refresh workflow

The generated-artifact isolation gate (067635cb51) landed mid-flight;
source PRs now carry en.ts only.
2026-07-16 20:04:12 -07:00
Peter Steinberger
7b296ae266 feat(ui): verify-connection affordance and device-code wizard E2E for Model Setup (#109183)
* feat(ui): add verify-connection affordance and device-code wizard e2e to Model Setup

* fix(ui): drop unnecessary Boolean conversion in canVerify

* chore(ui): reconcile i18n baselines after rebase
2026-07-16 11:11:04 -07:00
Peter Steinberger
cf029ea29e feat(agents): screen tool drives Control UI layout 2026-07-16 05:43:02 -07:00
Peter Steinberger
68694599af fix(exec): resolve no-route approvals immediately (#108935)
Fixes #104413. Supersedes the implementation direction in #104923 after preserving its contributor work and extending route detection across approval clients.

Co-authored-by: RickLin <83101411+ObliviateRickLin@users.noreply.github.com>
2026-07-16 04:26:38 -07:00
Peter Steinberger
4b904e6ac8 feat(ui): guided Model Setup page — web/Linux equivalent of the macOS Connect-your-AI flow (#108868)
* feat(ui): add guided Model Setup page for inference onboarding

* fix(ui): regenerate i18n locale bundles and narrow model-setup exports for CI gates

* chore(ui): regenerate i18n baselines after rebase

* chore(ui): translate model-setup strings for all locales
2026-07-16 04:16:27 -07:00
Peter Steinberger
2488d794ca feat(ui): expand child sessions in sidebar (#108838)
* feat(ui): expand child sessions in sidebar

* test(ui): type child session list options

* refactor(ui): split child session data helpers

* fix(ui): preserve session link semantics

* fix(ui): retry incomplete child session loads

* chore: keep release changelog owner-only
2026-07-16 03:26:49 -07:00
snowzlmbot
fdaae75645 fix(ui): expose derived session titles accessibly (#96267)
* fix(ui): improve accessible session history picker

* fix(ui): clean session picker ARIA semantics

* fix(ui): preserve derived titles after session patches

Reuse the most recent sessions.list options when refreshing after sessions.patch so derived-title hydration survives normal patch flows. Add unit and browser E2E coverage for patch refreshes retaining readable sidebar titles.

* test(ui): split session list option coverage

---------

Co-authored-by: snowzlmbot <snowzlmbot@users.noreply.github.com>
Co-authored-by: snowzlmbot <293528334+snowzlmbot@users.noreply.github.com>
Co-authored-by: Peter Steinberger <steipete@gmail.com>
2026-07-16 01:53:37 -07:00
Peter Steinberger
3c8269ca52 refactor(codex)!: fold the codex text provider into openai with a doctor migration
The live codex text provider was a redundant projection of the openai
catalog (exclusive provider ownership; the openai plugin's ChatGPT OAuth
discovery already serves gpt-5.6-* route-aware). Folding it:

- extensions/codex no longer registers a text provider, catalog entry, or
  synthetic text auth; provider.ts/provider-catalog.ts/provider-discovery.ts
  and the route-blind model-name heuristics are deleted; the narrow
  post-harness reasoning fallback moves to an app-server-owned module
- openai thinking policy keys on explicit selected-route provenance
  (api === openai-chatgpt-responses) instead of value-shape inference
- models.list gains an optional additive agentRuntime field (configured
  intent); session agentHarnessId remains the execution proof
- doctor --fix migrates the shipped codex/* config shape end to end:
  every model slot, provider-config merge with blocker-aware conflict
  handling, sessions, cron payloads (two-phase: runtime policy persists
  before cron refs rewrite), transcripts; migrated refs carry model-scoped
  agentRuntime.id=codex preserving the shipped wizard semantics; auto
  runtime policies normalize to codex with sibling fields preserved;
  blocked provider conflicts retain the whole legacy namespace fail-closed
  with an actionable warning
- the stale openai:default profile cleanup (#91352) was deliberately
  deferred to a follow-up after review showed it needs per-agent identity
  proofs; doctor keeps warning about unusable profiles

Fixes #105561
Fixes #84637
Fixes #90420
2026-07-16 03:06:43 +01:00
Peter Steinberger
4f0e131cd2 feat(ui): run sessions on cloud workers (#107670)
* feat(ui): add cloud session targets

* test(ui): cover cloud session attachments

* test(ui): use recovery token fixture

* test(ui): record cloud locale fallbacks

* fix(ui): harden cloud session recovery

* fix(ui): track cloud handoff phase

* fix(ui): close cloud recovery escape paths

* fix(ui): finish cloud recovery hardening

* fix(ui): recover ambiguous cloud session creation

* fix(ui): isolate stale cloud creation recovery

* test(ui): preserve cloud recovery literals

* fix(ui): complete cloud session release artifacts

* chore: move cloud release note to PR body

* docs(ui): name cloud session menu exactly
2026-07-14 12:44:11 -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
2ecc6b6b6b fix(ui): show restart banner for unapplied config (#107577)
* fix(ui): derive config apply state from gateway

* test(ui): align applied config hash coverage

* test(ui): follow config autosave flow

* fix(ui): guard applied config refreshes

* fix(ui): reconcile patched config revisions

* fix(ui): prevent stale config apply polling

* chore: leave release notes to release flow

* refactor(config): split applied revision helpers

* style(config): format gateway methods

* fix(i18n): refresh Korean native glossary hash
2026-07-14 08:43:35 -07:00
Peter Steinberger
9ab3d09f4d fix(terminal): recover sessions after stale Control UI connections (#107419)
* fix(terminal): harden reconnect recovery

* style(terminal): simplify recovery branch

* fix(terminal): handle session picker failures

* fix(terminal): refresh generated surfaces

* fix(terminal): translate session picker labels

* fix(terminal): ignore stale detach after rebind

* fix(terminal): preserve offsets through coalescing

* fix(i18n): refresh Korean native glossary hash

* fix(terminal): serialize picker adoption
2026-07-14 08:27:33 -07:00
Peter Steinberger
4319ddbe8c feat(control-ui): import Codex and Claude Code memory (#106406)
* feat(control-ui): import coding assistant memory

* test(migrate): clean memory import temp dirs

* chore: move memory import note to PR body

* build: refresh memory import generated artifacts

* fix(control-ui): complete memory import checks

* build(control-ui): localize memory recovery labels

* fix(control-ui): harden memory import recovery

* refactor(migrate): keep memory import surfaces bounded

* fix(control-ui): use canonical agent row type

* fix(codex): drop dead migration type exports

* fix(migrate): restrict imported memory permissions

* fix(control-ui): preserve memory import recovery state

* fix(control-ui): retain memory import results

* build(control-ui): preserve translation memory history

* fix(control-ui): bind memory import state to agent

* fix(control-ui): unlock memory import after refresh

* test(gateway): preserve memory method suffix

* fix(migrate): bind reviewed memory imports

* fix(migrate): make memory imports retry-safe

* perf(ui): keep memory import lazy

* build: refresh generated artifacts after rebase

* chore: keep migration runtime within LOC guard

* build: refresh Swift protocol model
2026-07-13 15:30:06 -07:00
Peter Steinberger
995c75baa0 fix(ci): restore current-main quality gates (#106751)
* fix(ci): restore Control UI quality gates

* fix(ci): repair dead export cleanup fallout

* fix(ci): repair latest main quality gates

* fix(ci): satisfy current-main gate contracts

* docs: format Cloud Workers guide

* test: isolate context lookup module
2026-07-13 13:54:03 -07:00
Peter Steinberger
bfe2786957 refactor(ui): remove dead exports (#105979)
* refactor(ui): remove dead exports

* chore(deadcode): refresh export baseline

* refactor(gateway): privatize chat media fields
2026-07-13 11:32:00 -07:00
Peter Steinberger
9166b23318 feat: configure model providers from the Control UI settings page (#106490)
* feat(gateway): add models.probe RPC, credential provenance, targeted auth logout

* feat(ui): configure model providers from settings — keys, probes, logout, defaults

* docs: Control UI provider configuration section

* fix(ui): confirm fallback shrinkage via replacePaths; guard model catalog refresh races; scanner-safe probe fixtures

* test(models): scanner-safe probe fixture identifier

* chore(i18n): resync model-providers strings after rebase

* fix(gateway-protocol): drop duplicate probe type imports after rebase

* chore(protocol): regenerate Swift client for probe field order

* chore(i18n): resync model-providers strings after main rebase

* test(ui): scope model-providers E2E to settings-section headings

* fix(models): isolate marker probes from stored profiles; emit no_model for config-only providers [AI]

* fix(models): honor configured auth mode for env probes; probe config-bound profiles past auth.order [AI]

* fix(gateway): resolve provider auth aliases in models.probe [AI]

* fix(gateway): scope targeted auth logout to skip provider-wide run abort [AI]

* fix(models): probe requested provider for overrides; unregister ephemeral probe DB [AI]

* fix(gateway): exclude local no-auth markers from models.authStatus API-key provenance [AI]

* chore(i18n): resync model-providers strings for landing
2026-07-13 11:23:34 -07:00
Peter Steinberger
f87a74602a refactor(gateway): simplify canonical WebSocket client (#106316)
* refactor(gateway): simplify canonical websocket client

* refactor(gateway): keep protocol options internal
2026-07-13 05:34:57 -07:00
Peter Steinberger
7c9b8baa2b refactor(gateway): consolidate TypeScript WebSocket clients (#106113)
* refactor(gateway): unify websocket clients

* fix(gateway): preserve adapter lifecycle behavior

* test(gateway): keep reconnect proof black-box

* chore(gateway): satisfy shared client lint

* refactor(gateway): keep protocol decisions internal

* refactor(gateway): preserve shared reconnect supervision

* test(gateway): use canonical browser barrel

* fix(gateway): resolve browser retry workspace source

* refactor(gateway): tighten shared protocol types
2026-07-13 03:08:21 -07:00
Peter Steinberger
7761022048 fix(ui): explain skipped cron runs (#105858) 2026-07-12 20:05:11 -07:00
Vincent Koc
c9012f2037 refactor(ui): trim private API type exports (#105772) 2026-07-13 08:11:24 +08:00
Peter Steinberger
3d9b912b88 feat: sidebar session state slot, worktree/automation badges, archive disables bound cron jobs (#104730)
* feat(gateway): flag sessions with attached automations and disable bound cron jobs on archive

Session rows now carry hasAutomation, derived from a lifecycle-owned index
over the cron service's in-memory jobs; cron events push refreshed rows so
badges stay live. sessions.patch { archived: true } disables enabled cron
jobs bound to the session (locked binding re-check, internal/operator-admin
callers only); restore intentionally does not re-enable them.

Refs #104700

* feat(ui): sidebar session state slot and worktree/automation badges

The run spinner moves into a leading state slot shared with the unread dot,
keeping the timestamp visible during runs; muted fork/clock badges sit after
the title (outside the trail/action overlap so pinned rows and touch devices
keep them). New strings localized via ui:i18n:sync (English fallback pending
a keyed translation run).

Refs #104700

* test(gateway): pin cron binding broadcast test to the event mechanism

The shard shares one process; session-store state from earlier tests can make
the row load return null, which legitimately produces a keyless refresh
payload. Row-field projection stays covered by session-utils and
session-automation-index tests.
2026-07-12 06:19:01 +01:00