feat(frontend): panneau Settings Deployment et gateway serveur desktop (#68 F1+F2)
Donne à l'utilisateur la surface pour activer le serveur depuis l'app. - `features/settings/` : `SettingsView`, `DeploymentSettings`, `useDeployment`. - `adapters/desktopServer.ts` + port `DesktopServerGateway` et DTO associés ; adapters mock et http/unsupported alignés (le mode web n'expose pas le contrôle du serveur qui l'héberge). - `ProjectsView` : le `showSettings: boolean` devient une navigation interne `AI Profiles` / `Deployment`. Le libellé alternant « Close AI Profiles » disparaît — Settings existait déjà dans cette vue, la surface évolue au lieu d'ajouter un `PanelId`. CORRECTION D'UN BRIEF FAUX, remontée spontanément par DevFrontend et qui mérite de survivre : le cadrage décrivait le mode `remoteProxyOtherMachine` avec deux champs. `validate_settings` en exige un troisième, `lanBindAddress`, et rejette loopback comme unspecified. Construit selon la spec, chaque save et chaque start en mode 3 aurait échoué — le lot serait parti vert et cassé. Le panneau expose donc un select alimenté par `candidateLanAddresses` fourni par le backend : la règle « le frontend n'invente jamais une IP » tient. QA ré-exécutée par Git avant merge : `npm run typecheck` exit 0 · `npx vitest run` 87 files / 789 passed, 0 échec. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
@ -15,6 +15,7 @@ import type {
|
||||
DomainEvent,
|
||||
EmbedderEngines,
|
||||
EmbedderProfile,
|
||||
EmbeddedServerStatus,
|
||||
FirstRunState,
|
||||
GitBranches,
|
||||
GitCommit,
|
||||
@ -41,6 +42,8 @@ import type {
|
||||
ProfileAvailability,
|
||||
ResumableAgent,
|
||||
ReplyChunk,
|
||||
ServerExposurePreview,
|
||||
ServerExposureSettings,
|
||||
Skill,
|
||||
SkillScope,
|
||||
Sprint,
|
||||
@ -678,6 +681,52 @@ export interface ModelServerGateway {
|
||||
): Promise<ModelServerCommandPreview>;
|
||||
}
|
||||
|
||||
/**
|
||||
* Embedded web server lifecycle + exposure settings (ticket #68). Backs the
|
||||
* desktop `Settings → Deployment` surface, so the user can expose IdeA to
|
||||
* remote devices without a command line.
|
||||
*
|
||||
* **Desktop-only.** Only the Tauri transport implements it for real; the web
|
||||
* transport rejects (a web client is *served by* this server and must not
|
||||
* reconfigure it). See `desktop-only.test.ts`.
|
||||
*
|
||||
* The backend owns every network fact: LAN candidates and the proxy upstream
|
||||
* URL come from {@link previewExposure}, never from client-side derivation.
|
||||
*/
|
||||
export interface DesktopServerGateway {
|
||||
/** Reads the persisted exposure settings. */
|
||||
getExposureSettings(): Promise<ServerExposureSettings>;
|
||||
/**
|
||||
* Validates and persists exposure settings. Rejects with a `GatewayError`
|
||||
* (`INVALID`) when the config is inconsistent — e.g. a remote mode without an
|
||||
* `https://` `publicOrigin`, or `remoteProxyOtherMachine` without a concrete
|
||||
* `lanBindAddress` / a non-empty `trustedProxies`.
|
||||
*/
|
||||
saveExposureSettings(settings: ServerExposureSettings): Promise<void>;
|
||||
/**
|
||||
* Derives LAN candidates, the upstream URL and non-fatal warnings for a
|
||||
* **draft** config, without persisting it. The single source of truth for the
|
||||
* addresses the UI displays.
|
||||
*/
|
||||
previewExposure(
|
||||
settings: ServerExposureSettings,
|
||||
): Promise<ServerExposurePreview>;
|
||||
/** Current server status. */
|
||||
status(): Promise<EmbeddedServerStatus>;
|
||||
/** Starts the server with the persisted settings; resolves with the new status. */
|
||||
start(): Promise<EmbeddedServerStatus>;
|
||||
/** Stops the server; resolves with the new status. */
|
||||
stop(): Promise<EmbeddedServerStatus>;
|
||||
/**
|
||||
* Observes status transitions. The backend emits no status event today, so
|
||||
* the Tauri adapter polls `embedded_server_status`; the schedule is a
|
||||
* transport detail owned by the adapter, and callers must not depend on it.
|
||||
*/
|
||||
onStatusChanged(
|
||||
handler: (status: EmbeddedServerStatus) => void,
|
||||
): Promise<Unsubscribe>;
|
||||
}
|
||||
|
||||
/** Input for {@link EmbedderGateway.saveEmbedderProfile}. */
|
||||
export interface SaveEmbedderProfileInput {
|
||||
profile: EmbedderProfile;
|
||||
@ -1076,6 +1125,7 @@ export interface Gateways {
|
||||
remote: RemoteGateway;
|
||||
profile: ProfileGateway;
|
||||
modelServer: ModelServerGateway;
|
||||
desktopServer: DesktopServerGateway;
|
||||
template: TemplateGateway;
|
||||
skill: SkillGateway;
|
||||
memory: MemoryGateway;
|
||||
|
||||
Reference in New Issue
Block a user