Commit Graph

9 Commits

Author SHA1 Message Date
Peter Steinberger 4af09d4961 feat(ui): unify focused presentation routes (#126143)
* feat(ui): unify focused presentation routes

/focus/<target> replaces unshipped standalone query links across dashboard, terminal, desktop, and native apps.

Gateway-served index assets are anchored so nested documents resolve their bundles from the Control UI base path.

* test(gateway): narrow emitted asset URLs

Fixes check:test-types TS18048/TS2322 by dropping unmatched optional captures before comparing emitted asset URLs.

* test(docs): follow centralized cloud secret guidance

Fixes the stale current-main docs test after #126132 centralized GCP and Hetzner setup in docker-vm-runtime.

* test(ui): retry missing locator reads

The 500ms locator text read can time out while the menu label is still rendering, causing expect.poll to reject instead of using its owning 10s retry window. Treat only Playwright TimeoutError as a missing value so the outer poll retries while page-closure and arbitrary failures still surface.

* test(android): capture TLS probe coroutine

The TLS probe test inferred its coroutine from mutable scope children, racing unrelated child startup and teardown in CI. Capture the exact Job from inside the probe coroutine and join that owner before asserting the stale-attempt guard.

* fix(gateway): preserve plugin focus routes

Keep approval handling ahead of plugin dispatch, but treat focus documents as an unclaimed Control UI fallback after plugin authentication and routing. Exact and prefix plugin routes therefore retain ownership, while unclaimed reads serve the focus document and other methods return 404.

* fix(ui): migrate released terminal links

Preserve stable v2026.7.1 terminal query compatibility by rewriting the root/base ?view=terminal URL once to the canonical /focus/terminal path with history.replace. Keep URL parsing path-only, and leave the removed desktop and dashboard query forms as a hard cut.

* test(codex): assign run-attempt tools shard

Cached filtered configs caused duplicate ownership, and the test lacked a canonical full-suite owner.

* test(ui): keep cloud recovery proof state-owned

The recovery test should assert owner state and reload identity, while dedicated tests own transient alert visibility.

* test(qa): wait for outbound bus state

* fix(qa): reserve gateway ports through staging

* refactor(qa): keep socket creation in gateway owner
2026-08-19 03:41:29 -07:00
Peter Steinberger 27b77a901e feat(ui): make session references first-class links with titled chips and hovercards (#125014)
* feat(sessions): teach session tools the Control UI link rule

Gate guidance on publicOrigin plus enabled Control UI, with exact literal-URL fallback after short-link misses.

* feat(ui): linkify session keys in chat markdown

Match agent session keys structurally in plain text and inline code, then delegate canonical chat navigation.

Allowlist data-session-key through markdown sanitization.

Pathfinder: keep internal Control UI route anchors in-app by removing target="_blank" and external-link rel attributes while preserving external link behavior.

* feat(ui): session hovercard + titled session chips backed by controlUi.sessionPreview

* fix(gateway): scope controlUi.sessionPreview to caller-visible sessions

Hover previews now apply the same createSessionListEntryFilter predicate as
sessions.list, so identity-bearing non-admin callers cannot preview-by-key
incognito rows or non-owner drafts the sidebar hides. Regression test proves
the viewer/admin split; pre-fix run leaked ok-status metadata.

* feat(sessions): carry the session-link rule in tool result envelopes

Deferred-description mode hides prose tool descriptions at decision time. Carry the shared Control UI session-link sentence in successful session lookup result envelopes so every tool mode sees the rule.

* fix(ui): upgrade session chips on appearance, not first pointer event

* fix(android): regenerate gateway protocol methods

* test(gateway): track session preview release train

* perf(ui): lazy-load session hovercard registration

* fix(ui): keep session hovercards off sidebar navigation

* fix(ui): cancel routed session-link navigation

* fix(sessions): advertise forced-literal ~key URLs so short-ID collisions cannot misroute

* test(sessions): update forced-literal guidance expectation

* fix(ui): collision-proof raw-key navigation and SPA-route internal session URLs

* perf(ui): preserve session route lazy boundary

* fix(ui): defer unseeded session-preview fetches to hover intent

* fix(sessions): hard-cap the model-visible session-link base
2026-08-17 04:05:02 -07:00
Amp f01960ca50 refactor(session-url): centralize shared grammar
Amp-Thread-ID: https://ampcode.com/threads/T-019ff438-3b93-77b8-9828-1d3c586cb127
2026-08-12 07:58:43 -07:00
Peter Steinberger e40e352fe7 refactor(session-url): centralize normalization and contract tests (#120945)
* refactor(session-url): centralize contract normalization

* fix(ui): resolve normalization agent-id alias

* test(session-url): make grammar tables type-safe
2026-08-09 02:56:07 -07:00
Peter Steinberger c708b41af4 fix(beam): open uploads at canonical catalog URLs (#120927)
* fix(beam): emit canonical catalog URLs

* fix(beam): type readonly runtime config

* fix(gateway): keep minimal metadata startup lazy

* chore(plugin-sdk): refresh API baseline
2026-08-09 02:09:01 -07:00
Peter Steinberger 0b85f9c174 feat: resolve short session references in the gateway (#120512)
* feat(gateway): resolve short session references

* refactor(ui): delegate short session resolution to gateway

* fix: complete short session resolver integration

* fix(gateway): filter deleted-agent short sessions

* fix(ui): support older gateway short links

* docs(web): qualify short-link candidate limits for older gateways

* refactor(protocol): split session resolve schema

* fix(gateway): filter session resolver visibility
2026-08-08 12:52:06 -07:00
Peter Steinberger b8e7f27ff2 feat(ui): let a link's slug settle a shared short-id prefix (#114486)
* feat(ui): let a link's slug settle a shared short-id prefix

Two sessions can share the first block of their uuid, which sent an otherwise
exact link to the disambiguation view even though the slug in that link already
said which session was meant. Capture the slug on short references and use it to
break the tie.

It can only narrow: a slug matching none or several of the tied sessions leaves
the chooser alone, and a reference that already resolves uniquely is untouched.
Generated links stay at their normal length instead of growing a full uuid.

* fix(ui): never settle a slug tie from an incomplete search

A truncated candidate set is an unfinished search, not a tie: an unexamined page
could hold the same short-id prefix under the same slug. Settling there would be
the guess the bounded search exists to avoid, so keep the chooser.
2026-07-27 06:08:51 -04:00
Peter Steinberger af552d4bc6 feat(ui): resolve session URLs through the gateway with best-effort slug matching (#114422)
* feat(ui): resolve session URLs through the gateway with best-effort slug matching

Session URLs now resolve a stored board face and a display-name slug through
the gateway instead of guessing from the browser's cached session page.

- An uncached open marks only the in-app navigation, never the shareable href,
  so the chat loader can re-derive the face and replace the URL.
- A cached row settles the lookup locally, keeping navigation off the wire.
- A one-segment reference resolves short id, then literal key, then display-name
  slug; ties reuse the existing disambiguation view.

* refactor(ui): keep slug ties on short disambiguation prefixes

Slug candidates reused the full uuid, which produced 32-character links in the
disambiguation view. uniqueShortIdPrefix already falls back to the full id when
the bounded search was truncated, so reuse it and drop the flag.

* fix(ui): navigate worktree owner links in-app so the face marker survives

The Worktrees owner link was a bare anchor consuming only the shareable href,
so preferenceDerivedFace was a no-op there and an uncached owner always opened
on chat. Match the other session surfaces: keep the clean href and navigate
with the options on plain clicks.

* fix(ui): search the first uuid block so long session references resolve

The gateway matches sessions.list search as a plain substring and stored keys
hold a hyphenated uuid, so any hyphen-stripped reference past the first block
matched nothing and 404'd. This hit disambiguation links, which offer prefixes
longer than eight characters. Send the first block and keep applying the full
prefix per row.

A resolved slug now canonicalizes to that same short reference instead of a
full uuid, so /chat/main/deploy-monitor settles on -6db92d48.

* docs(ui): record why the face marker stays out of shareable hrefs
2026-07-27 04:31:33 -04:00
Peter Steinberger cca5b14785 feat(ui): path-based session and dashboard URLs (#113883)
* feat(ui): path-based session and dashboard URLs

* docs(ui): document control UI URLs

* fix(ui): finalize session path routing

* feat(ui): anchor session URLs on stable keys

* docs(ui): clarify stable session URL identity

* fix(ui): resolve session prefixes with full prefix and pagination

Query sessions.list with the full supplied prefix instead of an eight-char
truncation, and paginate up to a bounded page count so longer disambiguation
links resolve instead of being reported ambiguous. Zero strict-prefix matches
now fall through to literal-key resolution rather than rendering an empty
ambiguity view.

Also document the ~dot/~dotdot segment escape: peer ids reach session keys
trimmed and lowercased only (src/routing/session-key.ts), so a literal '.' or
'..' segment is reachable and browsers would normalize it away.

* fix(ui): synchronize committed session routes

* test(ui): split native shell host coverage

* fix(ui): thread configured mainKey through session URL builders

Reserved-set disambiguation needs the operator-configured mainKey at runtime, so
thread it from agentsList through every session path builder and the ClickClack
control URL. Unambiguous non-hex single-segment rests now resolve literally while
short-id-shaped rests still fail closed, which restores ClickClack channel
compatibility detection and control-link reconciliation.

Also bound prefix-resolution retries, preserve catalog thread identity, and keep
draft state on ambiguous candidate links.

* fix(ui): repair session URL CI integration

* perf(ui): lazy-load session route resolution

* perf(ui): isolate session prefix resolution

* perf(ui): defer session path parsing

* perf(ui): defer session navigation startup

* fix(ui): preserve first-run and literal session navigation

* fix(ui): satisfy session routing type and export gates

* fix(clickclack): preserve unscoped control link agent

* style(ui): satisfy chat page line limit

* refactor(ui): move chat page helpers to owning modules

* fix(ui): preserve destination session route identity

* fix(ui): preserve agent identity in session routes

* fix(ui): escape dots in literal session path segments

encodeURIComponent leaves periods intact, so a literal key segment like
channel:release.js produced /chat/main/channel/release.js. In-app navigation is
intercepted by the SPA, but a refresh, an external link, or a ClickClack link
would be served as a static asset request and never reach the app.

pathForWorkboardBoard already escapes dots for this reason; mirror it in both the
session URL contract and the ClickClack encoder, route the agent id through the
same segment encoder, and pin the case in both shared vector tables.

* fix(ui): stop bootstrap after teardown race

* refactor(ui): centralize session navigation targets

* fix(ui): consume bootstrap teardown abort

* fix(ui): canonicalize configured main session routes

* fix(ui): preserve distinct session references

* fix(ui): redirect released session query links

* fix(ui): make bootstrap teardown abort-safe
2026-07-26 12:46:04 -04:00