Skip to content

feat(chat): open connector and channel setup in reusable overlays - #1707

Merged
ctkm-aelf merged 3 commits into
rollup-2026-09-29-ctkm-1from
nyxbot-connector-setup-modals
Sep 30, 2026
Merged

ctkm-aelf merged 3 commits into
rollup-2026-09-29-ctkm-1from
nyxbot-connector-setup-modals

Conversation

@ctkm-aelf

@ctkm-aelf ctkm-aelf commented Sep 30, 2026 •

Copy link
Copy Markdown
Collaborator

Summary

Clicking a connector or channel-bot setup link inside NyxChat now opens the existing setup content in an in-page overlay. The connector card appears directly with a close button, and chat stays in place through completion. Direct URLs continue to render their standalone pages.

  • A chat-owned adapter intercepts ordinary clicks on allowlisted, same-origin setup URLs. Modified clicks, external links and other destinations retain browser behavior. Shared link components remain unaware of overlays.
  • The standalone connector page and chat overlay render the same extracted ConnectLinkContent; channel setup uses an opt-in stayInPlace option with existing navigation defaults preserved. Both NyxBot and retained actor transcripts, including group chats, use the adapter. No backend or message-protocol changes.
  • Embedded OAuth reserves a provider popup during the submit gesture, stores recovery state in that popup before navigation, and polls status. Dismissal closes the window, ignores late responses and restores keyboard focus. Standalone OAuth and device-code flows remain supported.
  • Local fixtures now require explicit form submission: opening, waiting, filling or dismissing never completes setup. The manual demo URL /assistant?mock=1&nyxbot=1 persists the selected engine across navigation/reload. Demo credentials are synthetic and are not stored.

Test Plan

  • Production build, TypeScript and production mock-footprint check pass.
  • ESLint: zero errors (29 existing warnings).
  • New regression coverage for URL classification, overlay routing, popup recovery/lifecycle, theme preservation and keyboard focus.
  • Browser checks for both chat engines: pending while idle and after input, close/reopen, cancellation, explicit completion, one browser tab and unchanged chat URL; manual demo URL works without test-only initialization.
  • Interactive desktop/mobile inspection completed before the workspace daemon restart.
  • Full frontend unit suite: 3,970 tests in 389 files pass (npm run test -- --maxWorkers=3).
  • All 38 selected browser cases pass across the main run (36) and targeted rerun (2): overlay journeys, standalone channel setup and NyxAgent waiting flows.
  • CI on source head 9d6d4618: frontend lint/build, all 3,970 tests, coverage (71.01% lines; gate 15%) and wizard bundle freshness pass.
  • All CodeQL analyses (including Rust), Release Integrity Manifest and the CI gate pass; all source-head checks are green or intentional path/release skips.

The first broad local run passed 36 of 38 browser cases; the two failures were stale guide-link selectors in existing managed Telegram tests and have been corrected. Default-concurrency local unit runs hit unrelated routing/auth timing limits; the routing test passes alone, and the full suite passes with three workers and unchanged assertions. Live external OAuth providers were not exercised; provider recovery is covered by automated tests.

Initial Fable 5.1 adversarial review was completed. A later Fable review attempt was unavailable because Claude usage credits were exhausted. Independent final review found and verified fixes for popup recovery storage, dismissal during an in-flight request and focus restoration; its final pass reported no blocking findings.

Checklist

  • Follows project architecture: page/overlay adapters share reusable setup content.
  • No hardcoded secrets; fixture inputs are synthetic.
  • Error handling does not expose credentials or internal details.
  • Chat frontend and interactive-testing documentation updated.

Targets rollup-2026-09-29-ctkm-1 for inclusion in #1700.

@github-actions

Copy link
Copy Markdown

📊 Code coverage

Component Lines Threshold Status Δ vs base
Frontend (vitest) 71.01% 15% ✅ 🔻 -0.17

Gate: line coverage must stay at or above the threshold. Ratchet plan (W21): Backend → 55%, CLI → 50%, Frontend → 30% by quarter end.

@ctkm-aelf
ctkm-aelf merged commit 012dd86 into rollup-2026-09-29-ctkm-1 Sep 30, 2026
32 checks passed
ctkm-aelf added a commit that referenced this pull request Sep 30, 2026
* feat(auth): gate signup invitation codes behind default-on feature flag (#1690)

Signup invitation codes are now an operator choice. The requirement is behind
the global, default-on `auth:invitation-code` feature flag, which replaces the
`INVITE_CODE_REQUIRED` environment variable and can be toggled in
Admin > Feature Flags without a restart.

- Enabled (default): email signup requires a valid code; browser social signup
  can redeem one; native social token exchange still rejects first-time signup.
- Disabled: email and first-time social signup succeed without a code.
- Flag is global only; scoped overrides are rejected. The backend resolves it on
  every signup attempt and /api/v1/public/config reports the effective state.
- Invitation-code admin page, API and CLI are retained; the page states when
  codes are not required. Organization invitations are unchanged.
- Rollout: deploy backend before frontend. Deployments with
  INVITE_CODE_REQUIRED=false must disable the flag to keep signup open.

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

* docs(rollup): record 2026-09-29 ctkm-1 rollup

Records #1690 (default-on auth:invitation-code signup gate), its reviewed
head and squash commit, the main sync to e96a507, rollout notes and
verification.

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

* feat(oauth): redesign consent screen to match connection flows (#1701)

Rework the OAuth consent page into the centered card used by connect links
and channel-bot connections: circular NyxID mark, "Authorize application"
heading with the requesting app highlighted, plain-language permission rows,
and a trust note above Allow/Decline. Client ID, redirect and raw scopes move
under App details. The Low/Medium/High scope badges are removed; they were
client-side labels, not server decisions.

Service access shows each service's catalog description (two lines max) in a
scrollable list with edge fades. Customize toggles a picker that closes via
Done or Save selection. GET /user-services list responses now include
catalog_service_description. Form fields posted to
/oauth/authorize/decision are unchanged.

Adds a dev-only /oauth-consent-preview route with sample data and disabled
decisions.

Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com>

* test(nyxbot): wait for relayed message instead of a fixed sleep

the_same_question_is_not_worked_on_twice slept 300 ms after a Lark relay
callback that returns 202 before recording the message. The instrumented
coverage build on rollup PR #1700 took longer, so the reply target was not
yet recorded. Poll the home thread (bounded to 10 s) until it is, keeping
the assertions unchanged. Record the follow-up in the rollup notes.

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

* docs(rollup): record #1701 in the 2026-09-29 ctkm-1 rollup

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

* test(auth): allow the code-free registration test 5 s under coverage

The #1690 test 'allows email registration without a code when the flag is
disabled' failed once in the rollup's frontend coverage run: the register
call had not happened within waitFor's default 1 s. Use a 5 s timeout, as
other slow frontend waits do, and record the follow-up in the rollup notes.

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

* fix(billing): keep historical usage priced after price removal (#1702)

Re-authoring a service price deleted the retired Lago code's
billing_rate_cache row, so every historical usage_meter row recorded
under that code lost its only price and GET /billing/usage returned
null costs; the Usage page then showed Unavailable for the service and
for the Spend total. Grants were never the cause.

- Price removal marks the rate row retired_at instead of deleting it;
  new reservations refuse retired rates, historical pricing keeps
  reading them, and a re-synced price clears the mark.
- get_usage prices historical groups by grant-settled derivation, then
  the cached rate, then per-row reservation rates (exact Decimal128
  credits, as exact settlement does), else null with grant credits
  still known.
- The Usage page shows lower bounds (≥) with an unpriced-record count
  instead of Unavailable when only some records are unpriced.
- Docs: glossary precedence, admin usage limitation, rollout note.

Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com>

* docs(rollup): record #1702 in the 2026-09-29 ctkm-1 rollup

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

* ci: build backend test binaries with line-table debuginfo

Backend Test and Backend Billing Smoke died five times out of seven
attempts on the 2026-09-29 rollup head with exit 143 ("The runner has
received a shutdown signal") four to five minutes into compiling the
nyxid test binary, before any test ran. The full-DWARF test binary
exhausts the hosted runner's memory during codegen and linking. Both
jobs now set CARGO_PROFILE_TEST_DEBUG=line-tables-only, which keeps
panic locations and backtraces and changes nothing for local builds or
the coverage jobs.

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

* feat(chat): open connector and channel setup in reusable overlays (#1707)

* feat(chat): open connector and channel setup in reusable overlays

* fix(chat): harden setup popup lifecycle and restore link focus

* feat(channels): add tracked bot setup links and signed callbacks (#1705)

* feat(channels): add tracked bot setup links and signed callbacks

* fix(channels): preserve bot creation calls in production builds

* fix(cli): save bot webhook signing secrets to private files

* ci: bound backend coverage debug information

* docs: record bot-link callbacks and rollup verification

* fix(oauth): make Google Workspace grants optional (#1706)

* fix(oauth): make Google Workspace grants optional

Accept partial Google consent, remove seeded required-scope metadata across Workspace products, and show last reported grants in service details.

* test(oauth): match optional Workspace seed wording

* feat(oauth): show grants for every Google Workspace product

* test(oauth): retain prior scope evidence when response omits scopes

* ci: bound backend coverage debug info for hosted runners

* docs: record Google OAuth grant fix in rollup

---------

Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com>
ctkm-aelf added a commit that referenced this pull request Sep 30, 2026
* rollup: 2026-09-29 ctkm-1 integration into main (#1700)

* feat(auth): gate signup invitation codes behind default-on feature flag (#1690)

Signup invitation codes are now an operator choice. The requirement is behind
the global, default-on `auth:invitation-code` feature flag, which replaces the
`INVITE_CODE_REQUIRED` environment variable and can be toggled in
Admin > Feature Flags without a restart.

- Enabled (default): email signup requires a valid code; browser social signup
  can redeem one; native social token exchange still rejects first-time signup.
- Disabled: email and first-time social signup succeed without a code.
- Flag is global only; scoped overrides are rejected. The backend resolves it on
  every signup attempt and /api/v1/public/config reports the effective state.
- Invitation-code admin page, API and CLI are retained; the page states when
  codes are not required. Organization invitations are unchanged.
- Rollout: deploy backend before frontend. Deployments with
  INVITE_CODE_REQUIRED=false must disable the flag to keep signup open.

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

* docs(rollup): record 2026-09-29 ctkm-1 rollup

Records #1690 (default-on auth:invitation-code signup gate), its reviewed
head and squash commit, the main sync to e96a507, rollout notes and
verification.

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

* feat(oauth): redesign consent screen to match connection flows (#1701)

Rework the OAuth consent page into the centered card used by connect links
and channel-bot connections: circular NyxID mark, "Authorize application"
heading with the requesting app highlighted, plain-language permission rows,
and a trust note above Allow/Decline. Client ID, redirect and raw scopes move
under App details. The Low/Medium/High scope badges are removed; they were
client-side labels, not server decisions.

Service access shows each service's catalog description (two lines max) in a
scrollable list with edge fades. Customize toggles a picker that closes via
Done or Save selection. GET /user-services list responses now include
catalog_service_description. Form fields posted to
/oauth/authorize/decision are unchanged.

Adds a dev-only /oauth-consent-preview route with sample data and disabled
decisions.

Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com>

* test(nyxbot): wait for relayed message instead of a fixed sleep

the_same_question_is_not_worked_on_twice slept 300 ms after a Lark relay
callback that returns 202 before recording the message. The instrumented
coverage build on rollup PR #1700 took longer, so the reply target was not
yet recorded. Poll the home thread (bounded to 10 s) until it is, keeping
the assertions unchanged. Record the follow-up in the rollup notes.

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

* docs(rollup): record #1701 in the 2026-09-29 ctkm-1 rollup

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

* test(auth): allow the code-free registration test 5 s under coverage

The #1690 test 'allows email registration without a code when the flag is
disabled' failed once in the rollup's frontend coverage run: the register
call had not happened within waitFor's default 1 s. Use a 5 s timeout, as
other slow frontend waits do, and record the follow-up in the rollup notes.

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

* fix(billing): keep historical usage priced after price removal (#1702)

Re-authoring a service price deleted the retired Lago code's
billing_rate_cache row, so every historical usage_meter row recorded
under that code lost its only price and GET /billing/usage returned
null costs; the Usage page then showed Unavailable for the service and
for the Spend total. Grants were never the cause.

- Price removal marks the rate row retired_at instead of deleting it;
  new reservations refuse retired rates, historical pricing keeps
  reading them, and a re-synced price clears the mark.
- get_usage prices historical groups by grant-settled derivation, then
  the cached rate, then per-row reservation rates (exact Decimal128
  credits, as exact settlement does), else null with grant credits
  still known.
- The Usage page shows lower bounds (≥) with an unpriced-record count
  instead of Unavailable when only some records are unpriced.
- Docs: glossary precedence, admin usage limitation, rollout note.

Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com>

* docs(rollup): record #1702 in the 2026-09-29 ctkm-1 rollup

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

* ci: build backend test binaries with line-table debuginfo

Backend Test and Backend Billing Smoke died five times out of seven
attempts on the 2026-09-29 rollup head with exit 143 ("The runner has
received a shutdown signal") four to five minutes into compiling the
nyxid test binary, before any test ran. The full-DWARF test binary
exhausts the hosted runner's memory during codegen and linking. Both
jobs now set CARGO_PROFILE_TEST_DEBUG=line-tables-only, which keeps
panic locations and backtraces and changes nothing for local builds or
the coverage jobs.

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

* feat(chat): open connector and channel setup in reusable overlays (#1707)

* feat(chat): open connector and channel setup in reusable overlays

* fix(chat): harden setup popup lifecycle and restore link focus

* feat(channels): add tracked bot setup links and signed callbacks (#1705)

* feat(channels): add tracked bot setup links and signed callbacks

* fix(channels): preserve bot creation calls in production builds

* fix(cli): save bot webhook signing secrets to private files

* ci: bound backend coverage debug information

* docs: record bot-link callbacks and rollup verification

* fix(oauth): make Google Workspace grants optional (#1706)

* fix(oauth): make Google Workspace grants optional

Accept partial Google consent, remove seeded required-scope metadata across Workspace products, and show last reported grants in service details.

* test(oauth): match optional Workspace seed wording

* feat(oauth): show grants for every Google Workspace product

* test(oauth): retain prior scope evidence when response omits scopes

* ci: bound backend coverage debug info for hosted runners

* docs: record Google OAuth grant fix in rollup

---------

Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com>

* feat: NyxBot guests use specialists' services at owner-set levels; Telegram bot creators are owners; Lark groups answer only bot mentions (0.38.0) (#1712)

* fix: a Telegram bot created through NyxID knows its owner: the creating account is verified on link or first message, and Start greets instead of refusing

* fix: only a creator bound by the owner's own setup challenge is trusted, in private chats; link-time grants are audited and NyxBot keeps the verify link as a fallback

* chore: bump version to 0.37.2

* fix: guests use a specialist's services except deleting; Lark groups count only mentions of the bot itself

* fix: guests are refused calls that look like deleting by what they send, and never raise approvals; Lark bot ids cached per app

* fix: guest delete checks cover GETs, body method overrides, unparsable JSON and code fields; guests never run on the owner's approval grants

* feat: owners set what guests may do with each of a specialist's services (read, use, all), from the agent page or by asking NyxBot; destructive operations come from spec markers, not word lists

* test: agent fixtures carry guest_access

* fix: guest access judges every requested method, keeps levels beside grants for rolling deploys, honours read-only specs and catalog markers on mounted specs; Drive trash and content replace are destructive

* fix: grants form builds its request without an unused binding

* fix: guest calls never carry method overrides; Calendar event and Bitable record updates are destructive; a re-granted service starts at the default guest level

* fix: guests' default use is reading, creating and acting (no PUT/PATCH/DELETE); Aevatar's destructive markers stay unchanged and NyxID marks POST edits itself; only stored catalog contracts widen reads; override keys read as PHP reads them

* fix: NyxID's per-operation x-nyxid-changes-existing (true for POST edits, false for PUT actions); override checks follow the body's content type; hosted overlays mounted by URL are catalog contracts; all-level grants say they include deleting

* fix: only a catalog contract may say an operation only acts; method fields count when they name another changing verb, in JSON bodies too; ; separates fields; hosted overlays share one check

* fix: override checks skip empty, text and binary bodies; hosted overlay lookups share NyxID's compiled copy without cloning

* chore: bump version to 0.38.0

---------

Co-authored-by: chrono-kw <chrono-kw@users.noreply.github.com>

---------

Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com>
Co-authored-by: chronoai-kai <kaiweichronoai@gmail.com>
Co-authored-by: chrono-kw <chrono-kw@users.noreply.github.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant