feat: connect DevX — recents history, recency-ordered logins & keep-alive --watch#5
Merged
Merged
Conversation
- Add CLAUDE.md documenting stack, commands and architecture - Remove unused old/ (legacy Playwright-based implementation, replaced by the fetch-based FetchAuthClient) Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
…ogger) - test now runs once (vitest run); add test:watch for watch mode - add typecheck script (tsc) covering src + tests via tsconfig.typecheck.json, wired into CI; fixes latent test issues it surfaced (missing .js extensions, implicit any) - remove dead AppConfig fields (profiles, lastUsedProfile) - expose a shared logger singleton instead of re-creating it per module Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
POST now aborts after a configurable timeout (default 15s) so the CLI no longer hangs forever on an unreachable recette server, and network/abort failures are surfaced as readable AuthError messages. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
…ogic - inject IAuthClient into EnvSyncService (constructor, defaults to FetchAuthClient) so the orchestration is testable without network - extract the 4-branch credential resolution into ResolveCredentialsStep - extract environment resolution into a private resolveEnvironment method - dedupe the "replay last connection" logic into reconnectOptionsFromLast / describeLastConnectionApps, shared by the service and reconnect-last No behavior change. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
…ection) Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Drives runInteractive with a fake IAuthClient and a temp cwd (config, environments, discoverable app, saved profile) to cover: cookie injection into the app .env with preservation of existing vars, no-op on auth failure, and clean abort on unknown environment. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
…eshness Addresses three developer-experience asks around switching contexts and session expiry: - Multiple histories: replace the single lastConnection with a deduplicated recents history (cap 3, signed by env+login+app-set, timestamped). The interactive connect menu lists each recent combo for one-key replay, so juggling several topics/accounts no longer means redoing the whole flow. Migrates legacy lastConnection stores transparently. - Recency-first login ordering: ResolveCredentialsStep surfaces the most recently used logins first (alpha tiebreak), derived from the history. - Session freshness + opt-in --watch: capture the session cookie's Max-Age/Expires, show "connecté il y a Xh" /⚠️ in the recents menu and on connect, and add `connect --watch`. The watch flag is propagated through the quick-reconnect replay path. Auth client now exposes expiresAt; EnvSyncService extracts authenticateAndInject (shared by one-shot and watch). Tests cover dedup/cap/migration/getLoginRecency, cookie-expiry parsing, freshness helpers, and recents recording. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
The recette oneSessionId cookie carries no Max-Age/Expires (pure session cookie) and the server uses a sliding ~5 min inactivity timeout, so timer-based re-auth was guessing and forced a Vite reload on every tick. Instead, --watch now pings GET /auth/oauth2/userinfo (200 = alive) on an interval: while the session answers, the ping itself keeps the sliding server-side session alive, so nothing is rewritten and Vite never reloads. Re-auth + .env re-injection happen only when the probe reports the session is actually dead. - IAuthClient.isSessionAlive(envUrl, sessionId) + FetchAuthClient impl (shared fetch-with-timeout helper); GET with only the oneSessionId cookie. - runWatch rewritten as a keep-alive loop; --watch-interval <minutes>, default 2 min (kept below the observed ~5 min idle timeout so a ping refreshes the session mid-life rather than at expiry). - README updated; tests for isSessionAlive (mocked fetch). Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
app.config.json was versioned but held the per-developer appsRoot, so each dev had to edit it locally and avoid committing it (and a personal path leaked into git). User data was also split between config/app.config.json (repo) and ./.dev-auth-fetcher/credentials (cwd). Centralize all non-versioned per-user data into a single home folder ~/.dev-auth-fetcher/ (override via DEV_AUTH_FETCHER_HOME): config.json (appsRoot, defaultEnvironment) + credentials/<user>.json. Environment definitions stay versioned in the repo (config/environments/, shared defaults). loadAppConfig/loadUserCredentialsStore migrate the legacy cwd locations once. app.config.json is untracked and gitignored. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
damienromito
approved these changes
Jun 22, 2026
damienromito
left a comment
Member
There was a problem hiding this comment.
plein de choses... j'ai surtout testé l'outils et tout fonctionne bien
…nt CLI) Config & credentials already moved to the home dir; environments were the last piece still read from process.cwd()/config/environments, so the CLI only worked when launched from the repo root (a global `bin` install elsewhere found no environments — the likely "it doesn't find my config" reports). Environments now resolve from ~/.dev-auth-fetcher/environments/, seeded on first use from the code-level DEFAULT_ENVIRONMENTS (single versioned source of truth, bundled), with a one-time migration of a legacy config/environments/ if present. The redundant repo config/environments/*.json are removed. The whole runtime state (config + credentials + environments) now lives under the home dir. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Résumé
Améliore l'ergonomie de la commande
connect(historiques de connexion, tri des logins, mode--watchkeep-alive) et intègre une passe de revue technique du repo (outillage, refacto, robustesse réseau).Contexte
Retours de développeurs sur l'usage quotidien :
L'idée initiale d'auto-reconnect a été challengée : la vraie douleur est l'observabilité, pas l'automatisation. Vérifié en réel sur recette — le cookie
oneSessionIdn'a pas deMax-Age(timeout serveur ~5 min, glissant) etGET /auth/oauth2/userinfoest une sonde fiable. Le--watcha donc été conçu en keep-alive : un ping régulier maintient la session vivante sans toucher au.env(donc sans reload Vite), et ne ré-authentifie qu'en cas de chute réelle. Mécanique validée en run réel.En amont de ces features, une revue technique du repo a produit quelques correctifs d'outillage et de robustesse, inclus ici.
Changements
Ergonomie de
connectlastConnection.--watchkeep-alive (--watch-interval <min>, défaut 2) : ping/auth/oauth2/userinfo, ré-auth + réinjection.envuniquement si la session est tombée.Stockage centralisé hors du repo → CLI installable/globale
config/app.config.jsonétait versionné alors qu'il porte l'appsRootpropre à chaque dev (édité localement, à ne pas committer, et fuite d'un chemin perso dans git). Les données étaient en plus éparpillées (config dans le repo, credentials et environnements lus depuis lecwd), si bien que la CLI ne marchait que lancée depuis la racine du repo (unbininstallé globalement ne trouvait rien).~/.dev-auth-fetcher/(surchargeable viaDEV_AUTH_FETCHER_HOME) →config.json+credentials/<user>.json+environments/*.json. La CLI est donc indépendante ducwdet fonctionne en install global.DEFAULT_ENVIRONMENTS), seedée au premier usage ; lesconfig/environments/*.jsonredondants sont retirés du repo. (Ajouter un env partagé = éditer ce tableau ; un env perso = déposer un.jsondans le dossier ci-dessus.)config/app.config.json,./.dev-auth-fetcher/,config/environments/) au premier lancement ;config/app.config.jsonest dé-versionné et.gitignore.Revue technique (en amont)
old/(ancienne implémentation Playwright) ; ajout d'unCLAUDE.md.test=vitest run(+test:watch), scripttypecheck(src + tests) câblé en CI, suppression de champs morts de config, logger partagé.EnvSyncService+ injection deIAuthClient(orchestration testable sans réseau) ; dédup de la logique de reconnexion.FetchAuthClient: timeout (AbortController) et erreurs réseau lisibles ; capture de l'expiration cookie ; sondeisSessionAlive.Comment tester
Manuellement :
pnpm run dev connectdeux fois avec des logins/apps différents → le menu propose ensuite plusieurs reconnexions rapides (avec l'âge), et la liste d'identifiants remonte le dernier login utilisé en tête.pnpm run dev connect --watch→ toutes les 2 min :Session maintenue active.sans reload Vite ;Ctrl+Carrête proprement. Si la session tombe réellement →Session expirée — ré-authentification…puis réinjection.