feat(auth): force org selection in parse-prd and export commands

CHANGES:
- Add forcePrompt option to ensureOrgSelected utility
- When forcePrompt=true, always fetch orgs and prompt (if >1 org exists)
- Pre-select current org in dropdown when forcePrompt is used
- Show '(current)' label next to currently selected org in prompt

PARSE-PRD:
- Force org selection after authentication (forcePrompt: true)
- User can choose which org to create the brief in
- Auto-selects if only one org available

EXPORT:
- Force org selection after tag selection (forcePrompt: true)
- User can choose which org to export to
- Auto-selects if only one org available

INIT:
- Removed process.exit(0) hack that was incorrectly added

This ensures users explicitly choose (or confirm) their target organization
before creating briefs, preventing accidental exports to wrong orgs.
This commit is contained in:
Eyal Toledano
2025-12-02 12:06:23 -05:00
parent 985b6e16fa
commit f04a568de0
4 changed files with 44 additions and 13 deletions

View File

@@ -28,6 +28,7 @@ import { createUrlLink } from '../ui/index.js';
import { ensureAuthenticated } from '../utils/auth-guard.js';
import { selectBriefFromInput } from '../utils/brief-selection.js';
import { displayError } from '../utils/error-handler.js';
import { ensureOrgSelected } from '../utils/org-selection.js';
import { getProjectRoot } from '../utils/project-root.js';
/**
@@ -100,7 +101,7 @@ export class ExportCommand extends Command {
// Default action
this.action(async (options?: any) => {
return await this.executeExport(options);
await this.executeExport(options);
});
}
@@ -334,6 +335,25 @@ export class ExportCommand extends Command {
return;
}
// Force org selection after tag selection
// User can choose which org to export to, with current org pre-selected
const authManager = (this.taskMasterCore!.auth as any).authManager;
if (authManager) {
const orgResult = await ensureOrgSelected(authManager, {
promptMessage: 'Select an organization to export to:',
forcePrompt: true
});
if (!orgResult.success) {
console.log(chalk.gray('\n Export cancelled.\n'));
this.lastResult = {
success: false,
action: 'cancelled',
message: orgResult.message || 'Organization selection cancelled'
};
return;
}
}
// Handle multiple tags export
if (selectedTags.length > 1) {
await this.executeExportMultipleTags(selectedTags, options);

View File

@@ -27,6 +27,8 @@ export interface EnsureOrgOptions {
silent?: boolean;
/** Custom message to show when prompting */
promptMessage?: string;
/** If true, always prompt for org selection even if one is already set */
forcePrompt?: boolean;
}
/**
@@ -55,13 +57,13 @@ export async function ensureOrgSelected(
authManager: AuthManager,
options: EnsureOrgOptions = {}
): Promise<OrgSelectionResult> {
const { silent = false, promptMessage } = options;
const { silent = false, promptMessage, forcePrompt = false } = options;
try {
const context = authManager.getContext();
// If org is already selected, return it
if (context?.orgId) {
// If org is already selected and we're not forcing a prompt, return it
if (context?.orgId && !forcePrompt) {
return {
success: true,
orgId: context.orgId,
@@ -70,7 +72,7 @@ export async function ensureOrgSelected(
};
}
// No org selected - check if we can auto-select
// Fetch available orgs
const orgs = await authManager.getOrganizations();
if (orgs.length === 0) {
@@ -104,19 +106,28 @@ export async function ensureOrgSelected(
}
// Multiple orgs - prompt for selection
if (!silent) {
if (!silent && !context?.orgId) {
console.log(chalk.yellow('No organization selected.'));
}
// Set default to current org if one is selected
const defaultOrg = context?.orgId
? orgs.findIndex((o) => o.id === context.orgId)
: 0;
const response = await inquirer.prompt<{ orgId: string }>([
{
type: 'list',
name: 'orgId',
message: promptMessage || 'Select an organization:',
choices: orgs.map((org) => ({
name: org.name,
name:
org.id === context?.orgId
? `${org.name} (current)`
: org.name,
value: org.id
}))
})),
default: defaultOrg >= 0 ? defaultOrg : 0
}
]);