fix(auth): enforce org selection post-login and remove duplicate success messages

CHANGES:
- Add ensureOrgSelected to auth-guard.ts for all auth flows (existing & new sessions)
- Add ensureOrgSelected to parse-prd flow in commands.js (after authentication) -- NOT WORKING.
- Add ensureOrgSelected to init.js cloud storage flow (using shared utility)
- Remove duplicate 'Authentication successful!' boxen messages (auth.command.ts, auth-guard.ts)
- Export authenticateWithBrowserMFA and ensureOrgSelected from @tm/cli utils
- init.js now uses shared authenticateWithBrowserMFA instead of custom OAuth flow
- auth-guard.ts now checks context.orgId before making API calls (optimization)

FIXES:
- Org selection now happens after login in parse-prd, init, and export commands
- Single source of truth for browser auth with MFA support
- Removed redundant auth UI code from init.js

KNOWN ISSUES:
- tm init and tm export may hang after completion (Supabase auto-refresh timer)
- Root cause: AuthManager/Supabase client keeps event loop alive
- tm auth login works because it uses setupContextInteractive from ContextCommand
- Proper fix would be to add cleanup method to SupabaseAuthClient to stop auto-refresh
- Workaround (process.exit) was attempted but reverted as too dirty

The hanging issue requires further investigation into how auth login handles
cleanup vs how ensureAuthenticated/ensureOrgSelected interact with Supabase.
This commit is contained in:
Eyal Toledano
2025-12-02 11:42:32 -05:00
parent 1c889cccaa
commit 985b6e16fa
7 changed files with 95 additions and 92 deletions

View File

@@ -63,7 +63,7 @@ import {
validateDependenciesCommand
} from './dependency-manager.js';
import { checkAndBlockIfAuthenticated } from '@tm/cli';
import { checkAndBlockIfAuthenticated, ensureOrgSelected } from '@tm/cli';
import { LOCAL_ONLY_COMMANDS } from '@tm/core';
import {
@@ -383,6 +383,19 @@ async function handleParsePrdToHamster(prdPath) {
const authManager = AuthManager.getInstance();
// Ensure an organization is selected before proceeding
const orgResult = await ensureOrgSelected(authManager, {
promptMessage: 'Select an organization to create the brief in:'
});
if (!orgResult.success) {
console.error(
chalk.red(
`\n ${orgResult.message || 'Organization selection cancelled.'}\n`
)
);
return;
}
// Read PRD file content
const prdContent = fs.readFileSync(prdPath, 'utf-8');
if (!prdContent.trim()) {