fix: enhance error messages and documentation for team provisioning
- Updated error handling in TeamAgentToolsInstaller to provide clearer guidance on available domains, improving user experience. - Added an important note in TeamProvisioningService documentation regarding domain support, clarifying that "member" is not a valid domain. - Adjusted EditTeamDialog component for consistent styling by removing unnecessary class properties. Made-with: Cursor
This commit is contained in:
parent
0e627c4b3f
commit
faf042d640
4 changed files with 42 additions and 2 deletions
|
|
@ -1206,7 +1206,7 @@ async function main() {
|
|||
die('Unknown process action: ' + String(action));
|
||||
}
|
||||
|
||||
die('Unknown domain: ' + String(domain));
|
||||
die('Unknown domain: ' + String(domain) + '. Available domains: task, kanban, review, message, process. Run with --help for usage.');
|
||||
}
|
||||
|
||||
main().catch((err) => {
|
||||
|
|
|
|||
|
|
@ -423,6 +423,8 @@ function buildTeamCtlOpsInstructions(teamName: string, leadName: string): string
|
|||
` - Do NOT split when work is inherently sequential, requires one person to keep consistent context, or the overhead would exceed the benefit.`,
|
||||
` - When splitting, make each task have a clear completion criterion and a single accountable owner.`,
|
||||
``,
|
||||
`IMPORTANT: teamctl.js only supports these domains: task, kanban, review, message, process. There is NO "member" domain — team members are managed by spawning teammates via the Task tool, not via teamctl.`,
|
||||
``,
|
||||
`Task board operations — use teamctl.js via Bash:`,
|
||||
`- Create task: node "$HOME/.claude/tools/teamctl.js" --team "${teamName}" task create --subject "..." --description "..." --owner "<actual-member-name>" --notify --from "${leadName}"`,
|
||||
`- Assign/reassign owner: node "$HOME/.claude/tools/teamctl.js" --team "${teamName}" task set-owner <id> <member-name> --notify --from "${leadName}"`,
|
||||
|
|
|
|||
|
|
@ -124,7 +124,7 @@ export const EditTeamDialog = ({
|
|||
|
||||
return (
|
||||
<Dialog open={open} onOpenChange={(nextOpen) => !nextOpen && onClose()}>
|
||||
<DialogContent className="max-w-2xl sm:max-w-md">
|
||||
<DialogContent className="max-w-2xl">
|
||||
<DialogHeader>
|
||||
<DialogTitle>Edit Team</DialogTitle>
|
||||
<DialogDescription>Change team name, description and color</DialogDescription>
|
||||
|
|
|
|||
|
|
@ -8,6 +8,9 @@ import { getWorktreeNavigationState } from '../utils/stateResetHelpers';
|
|||
const logger = createLogger('teamSlice');
|
||||
|
||||
const TEAM_GET_DATA_TIMEOUT_MS = 30_000;
|
||||
function nowIso(): string {
|
||||
return new Date().toISOString();
|
||||
}
|
||||
|
||||
function withTimeout<T>(promise: Promise<T>, ms: number, label: string): Promise<T> {
|
||||
let timer: ReturnType<typeof setTimeout> | undefined;
|
||||
|
|
@ -138,6 +141,11 @@ export interface TeamSlice {
|
|||
lastSendMessageResult: SendMessageResult | null;
|
||||
reviewActionError: string | null;
|
||||
provisioningRuns: Record<string, TeamProvisioningProgress>;
|
||||
/**
|
||||
* Per-team lower bound for provisioning progress timestamps.
|
||||
* Used to ignore late progress events from a previous run after stop→launch.
|
||||
*/
|
||||
provisioningStartedAtFloorByTeam: Record<string, string>;
|
||||
leadActivityByTeam: Record<string, LeadActivityState>;
|
||||
activeProvisioningRunId: string | null;
|
||||
provisioningError: string | null;
|
||||
|
|
@ -231,6 +239,7 @@ export const createTeamSlice: StateCreator<AppState, [], [], TeamSlice> = (set,
|
|||
lastSendMessageResult: null,
|
||||
reviewActionError: null,
|
||||
provisioningRuns: {},
|
||||
provisioningStartedAtFloorByTeam: {},
|
||||
leadActivityByTeam: {},
|
||||
activeProvisioningRunId: null,
|
||||
provisioningError: null,
|
||||
|
|
@ -746,6 +755,18 @@ export const createTeamSlice: StateCreator<AppState, [], [], TeamSlice> = (set,
|
|||
},
|
||||
|
||||
createTeam: async (request: TeamCreateRequest) => {
|
||||
// Ensure provisioning progress subscription is active (defensive).
|
||||
get().subscribeProvisioningProgress();
|
||||
|
||||
// Establish a per-team floor so late events from a previous run can't override UI.
|
||||
const floor = nowIso();
|
||||
set((state) => ({
|
||||
provisioningStartedAtFloorByTeam: {
|
||||
...state.provisioningStartedAtFloorByTeam,
|
||||
[request.teamName]: floor,
|
||||
},
|
||||
}));
|
||||
|
||||
// Clear stale provisioning runs for this team so the banner starts fresh
|
||||
set((state) => {
|
||||
const cleaned = { ...state.provisioningRuns };
|
||||
|
|
@ -783,6 +804,18 @@ export const createTeamSlice: StateCreator<AppState, [], [], TeamSlice> = (set,
|
|||
},
|
||||
|
||||
launchTeam: async (request: TeamLaunchRequest) => {
|
||||
// Ensure provisioning progress subscription is active (defensive).
|
||||
get().subscribeProvisioningProgress();
|
||||
|
||||
// Establish a per-team floor so late events from a previous run can't override UI.
|
||||
const floor = nowIso();
|
||||
set((state) => ({
|
||||
provisioningStartedAtFloorByTeam: {
|
||||
...state.provisioningStartedAtFloorByTeam,
|
||||
[request.teamName]: floor,
|
||||
},
|
||||
}));
|
||||
|
||||
// Clear stale provisioning runs for this team so the banner starts fresh
|
||||
set((state) => {
|
||||
const cleaned = { ...state.provisioningRuns };
|
||||
|
|
@ -826,6 +859,11 @@ export const createTeamSlice: StateCreator<AppState, [], [], TeamSlice> = (set,
|
|||
},
|
||||
|
||||
onProvisioningProgress: (progress: TeamProvisioningProgress) => {
|
||||
const floor = get().provisioningStartedAtFloorByTeam[progress.teamName];
|
||||
if (floor && progress.startedAt < floor) {
|
||||
// Ignore late progress from a previous run (common after stop→launch).
|
||||
return;
|
||||
}
|
||||
set((state) => ({
|
||||
provisioningRuns: {
|
||||
...state.provisioningRuns,
|
||||
|
|
|
|||
Loading…
Reference in a new issue