# Architecture This document is the source of truth for dsh-AuthInOne's runtime ownership, extension requirements, data handling, and installation lifecycle. A release that conflicts with these rules is invalid even when its local build succeeds. ## Plugin boundary invariants / 插件边界不变量 dsh-AuthInOne is an independently installed DSH plugin bundle. Its source of truth is this repository, not a DSH checkout. Installing it must never require copying artifacts, linking a workspace, editing a profile by hand, or merging plugin business code into DSH. ### Plugin-owned code The plugin package exclusively owns: - the `AuthProviderAdapter` contract; OpenAI Codex and compatibility authorization transactions; PKCE, state, verifier, loopback and RFC 8628 device-flow handling; token refresh, logout, revocation, health, and redacted status; - the credential-reference namespace; Typert Remote DTOs and Host service; Provider mapping, connection tests, and model activation; - session-event aggregation; time, Provider, and output-price filters; price catalog and cost projections; Client token formatting; - vision-fallback policy, exact-route capability checks, auxiliary request/result provenance, provider-reported usage attribution, and request-local image-to-description substitution; - Models contributions, Auth modal, Usage section, calendar, dropdowns, progress bars, Usage icon, CSS modules, locale strings, and interaction copy; - compatibility behavior, migration code, README files, screenshots, and release metadata; - the explicit bootstrap CLI, exact-listener discovery, official plugin-command invocation, detached same-port restart supervisor, and credential-free restart status. None of those subjects may be implemented in a DSH core package, base/Web bundle, or built-in Provider module. The browser receives public authorization instructions and allowlisted status only. State, verifier, authorization code, device code, access token, and refresh token are Host-only values. ### Bundle-owned 47f compatibility owners Official DSH `47f9438` lacks the generic composition declarations needed by the product UI. AuthInOne does not modify that checkout. Its own Bundle disables only the two official `ui-settings-general` and `ui-settings-models` rows and mounts exact-source derivatives that preserve all native behavior while adding: 1. optional Models settings contribution slots for general information and actions; and 2. a keyed icon child slot projected by the Settings shell. The derived owner modules contain no AuthInOne, OAuth, Provider, pricing, Usage, or vision business logic. Their exact upstream commit and DeepSeek MIT notice ship in `THIRD_PARTY_NOTICES.md`. The Host fingerprints both official owner artifacts and fails loud on unknown/new DSH; the Client rejects already-declared seams. Without this plugin, the disabled overrides and inserted row disappear together, so the official rows resume automatically. If a released DSH API already supports a capability, the plugin must use it instead of adding another core seam. Every core diff is reviewed as a generic platform change independently from the plugin release. ### Forbidden dependencies The plugin must not: - import DSH source files, private paths, workspace-only aliases, or generated files at build or runtime; the attributed 47f owner derivatives are package-owned source files; - modify a DSH checkout, built-in Provider business logic, or native profile defaults; - monkey-patch the DOM, use global CSS, or scan local credential stores; - read or import `~/.codex/auth.json`, OpenCodex state, browser cookies or storage, OTPs, Keychain entries, or another product's token database; - make a competing plugin a runtime dependency or vendor its implementation. ## Runtime composition `cordis.patch.yml` disables the two exact official Settings owner rows and adds one package-owned Cordis row. The one Client entry internally mounts the generic compatible Settings owner, generic compatible Models owner, and then AuthInOne's business contributions. The Host entry starts `AuthInOneService`; package metadata lets DSH load the Client entry for a Web profile. The Host uses public DSH LLM, session, persistence, settings, credentials, attachment, and default-model services. Vision fallback listens on the public `llm/stream` waterfall. It acts only on loop-built requests whose exact main-model metadata explicitly omits image input. Native multimodal routes and routes with unknown modality metadata are delegated unchanged. The auxiliary route must explicitly declare image input. Its exact request and result use ordinary durable `user/message` events with merge-extensible message provenance, so no new DSH session-event type or core loop branch is required. Provider-bound main requests omit the plugin provenance rows and replace only image blocks whose durable descriptions exist. Registrations use Cordis effects, slot injectors, and returned disposers. Unloading the plugin disposes the Remote mount, slot contributions, service, stylesheet, listeners, and pending authorization transaction. Plugin CSS is module-scoped and the DSH client loader owns stylesheet removal. The Auth Host owns login transactions and credential refresh. OpenAI Codex is the stable browser-PKCE adapter. Kimi Code, xAI Grok, Anthropic, GitHub Copilot, Command Code, Cursor, Google Antigravity, and Kiro use the same transaction and credential lifecycle with explicit Experimental or Experimental compatibility labels. Qwen account OAuth is discontinued and cannot start. API-key, Plan/API-key, and custom OpenAI-compatible Provider editing remain separate DSH Models capabilities and never count as successful account Auth. The Auth Provider catalog is selection metadata, not a set of configured instances. Models projects only native/configured API profiles, live routes, and Auth accounts whose credential state is connected or requires reauthorization. Starting, cancelling, timing out, or failing an Auth transaction remains inside the Auth dialog and never creates a Models card. A successful or signed-out Auth transition invalidates the Client projection so the Models cards update without a page reload; OAuth instances use Provider-specific model health and logout rather than the generic Base URL probe. Every implemented Auth runtime activates its model adapter only after the DSH credential write completes. Cancellation compensates a credential write that finishes after the transaction was aborted. Refresh is single-flight and generation-safe. Logout deletes the local DSH credential and unregisters the route before any best-effort remote revocation. Disposal cancels the active transaction and unregisters every plugin-owned adapter. ## Install and uninstall lifecycle The supported install path is the package-owned bootstrap: ```sh pnpm dlx github:Stormycry-cryp/dsh-AuthInOne# install --profile web ``` The bootstrap may mutate the profile only by invoking the official `dsh plugin --profile add ` command. It must not copy runtime files into DSH, create a workspace link, patch a compiled DSH file, or require a manual profile edit. Before mutation it verifies a unique listener, recognizable DSH process, working directory, standard launcher, loopback target, and exact compatibility-owner artifacts. After successful mutation, a package-owned detached supervisor waits for the installer process to return, sends `SIGTERM` only to the validated listener PID, waits for that PID and port to close, starts standard `dsh web` in the resolved working directory on the original port, and waits for the original URL to become healthy. It never starts an alternate port. If launch provenance or compatibility cannot be proved, the existing Host remains running and the command fails loud. The serialized restart plan contains process identifiers, validated paths, public arguments, profile, URL, and timeouts only. It never contains environment values, credentials, Provider responses, authorization URLs, cookies, or request headers. Owner-only status under the selected profile records scheduled, stopping, starting, ready, or failed. A copied single-file supervisor is removed after success. The supported removal path is symmetric: ```sh pnpm dlx github:Stormycry-cryp/dsh-AuthInOne# uninstall --profile web ``` The bootstrap invokes the official `dsh plugin --profile remove dsh-auth-in-one` operation before the same validated replacement. After removal, the settings section, Models contributions, Remote namespace, Host service, styles, and subscriptions must be absent and native behavior must be restored. Removal deliberately preserves DSH sessions, plugin settings, and credential references. Deleting durable data is a separate, explicit user action. A later reinstall may recover non-sensitive plugin settings; secrets remain controlled by the DSH credentials provider. ## Compatibility and safe degradation The exact-47f compatible owners declare the three generic seats before AuthInOne registers business contributions through normal slot injectors. An unknown/new owner fingerprint or pre-existing native seam fails loud; the package never tries a partial DOM fallback. Authentication fails closed when credentials, Remote transport, LLM registration, or another required Host service is unavailable. An API key, a local Codex credential, or a pre-existing token file is never treated as a successful Auth login. The README compatibility table records the minimum verified DSH release or commit, each required seam, and the exact degraded behavior on the latest official tagged release. Credential-bearing outbound probes reject redirects so a Provider secret cannot follow an upstream redirect to another origin. OAuth, quota, model-catalog, and probe JSON responses use an incremental byte-limited reader in addition to request timeouts. Oversized or malformed responses fail closed without exposing upstream bodies through Remote or logs. The Client renders subscription quota only when an upstream response contains at least one complete percentage window. Missing, incomplete, unsupported, or failed quota responses do not create an error row, placeholder, or locally inferred allowance in Models. Release acceptance covers three installations: | Environment | Required evidence | | --- | --- | | Untouched official DSH `47f9438`, one package add | Auth, native Models behavior, vision settings, Usage/icon, Host/Remote, and disposal work end to end without `--patch` or a profile edit. | | Unknown/new DSH owner artifacts | Host guard fails with the explicit compatibility error before business state is created. | | Plugin removed | Plugin package row and bundle row are gone; UI, Remote, Host, styles, and listeners are absent; native settings still work. | ## Data and pricing DSH session logs remain the source of truth. Aggregates can be rebuilt without a plugin database. Main and vision-assist model calls use their actual request or completion event timestamps and retain separate call roles; tool calls are a separate dimension. Provider-reported input, output, cache-read, cache-write, and reasoning buckets are retained. Missing fields remain unknown. Costs are projections over versioned catalog rows. Each row records Provider, model, currency, source URL, verification date, effective date, and explicit per-million-token buckets. Output-price filtering uses only the USD output-token catalog bucket. A missing or non-USD output price is unpriced; no implicit currency conversion or fallback Provider price is allowed. User overrides replace only the exact Provider/model pair. Daily Token activity is a Client projection over the latest 365 calendar dates: seven weekday rows, up to 53 week columns, and explicit zero-value cells for dates with no matching calls. Only logged activity from the active time, Provider, and output-price filters controls color. Weekly and cumulative views retain their separate aggregation rules. Secrets live in DSH credentials. Image bytes live in DSH attachment storage. Non-sensitive plugin settings live in the plugin's settings namespace. Vision provenance stores attachment references, routes, prompt version, descriptions, stable failure codes, and upstream usage in DSH sessions; it stores neither bytes nor credentials. The Client receives only redacted connection metadata, authorization instructions, device user codes, configuration metadata, and aggregated usage. PKCE verifier, authorization code, device code, access token, and refresh token remain Host-only. Removing the plugin does not delete these DSH-owned sources. ## Automated boundary gates `pnpm verify:boundaries` checks the published bundle and plugin source for forbidden private-path imports, profile mutations, global stylesheet selectors, and missing lifecycle ownership. With `DSH_SOURCE_ROOT` set to a DSH checkout, the same gate additionally proves that core does not import this package and that the declared seam files contain no plugin business identifiers. DSH package tests separately prove contribution disposal and the section-icon fallback. Release verification must also run standard CLI add/remove/re-add acceptance and record the profile diff plus UI/Remote states. A static gate does not substitute for that lifecycle test. ## Collision and provenance decision AuthInOne reuses DSH's official extension seams and open protocols, not third-party plugin code. The surveyed projects each cover a useful slice—usage ledgers, Codex authentication, OpenAI-compatible adapters, cost storage, or Web statistics—but none is a runtime dependency. Their public capability boundaries informed collision analysis only. AuthInOne business logic, credential format, schema, tests, README text, and product interaction copy are independently written. The compatibility owner runtime is an attributed MIT derivative of the official DSH `47f9438` Settings sources; exact files and license are recorded in `THIRD_PARTY_NOTICES.md`. No community-plugin source, schema, copy, or visual is vendored. The committed Host bundle contains reviewed formal dependencies used for Provider transport: `@earendil-works/pi-ai` 0.82.1 under MIT and `@cursor/sdk` 1.0.24 under the Cursor SDK License and Terms of Service. Neither dependency grants access to another product's local credential store. They do not become separate profile dependencies during standard plugin installation.