task-output.ts2.2 KBView on GitHub
/**
 * The task OUTPUT axis — what finishing a task actually produces.
 *
 * Mirrors `TASK_OUTPUT_KINDS` in apps/server/src/db/aop-schema.ts — keep in sync. This axis
 * supersedes the old `taskChannel` declaration: `taskChannel` was written before the work
 * happened, `taskOutput.kind` reflects what the task really produces, so where the two disagree
 * the output kind wins. Note there is no `multi-action` kind — those tasks are `crm-field`,
 * `crm-opportunity` or `none` on this axis.
 *
 * `taskOutput` is NULLABLE and null is a real state: "the output is not decided yet". Surfaces
 * that bucket by kind must therefore give null a home of its own rather than folding it into
 * email.
 */
export const TASK_OUTPUT_KINDS = [
  'email',
  'slack',
  'calendar',
  'linkedin',
  'whatsapp',
  'crm-field',
  'crm-opportunity',
  'file',
  'recommendation',
  'none',
] as const;

export type TaskOutputKind = (typeof TASK_OUTPUT_KINDS)[number];

/** Bucket key for a task whose output kind has not been decided yet (`taskOutput` is null). */
export const UNDECIDED_OUTPUT_KEY=[redacted];

/** Human labels for each output kind — shared by every surface that names one. */
export const TASK_OUTPUT_KIND_LABELS: Record<TaskOutputKind, string> = {
  email: 'Email',
  slack: 'Slack',
  calendar: 'Calendar',
  linkedin: 'LinkedIn',
  whatsapp: 'WhatsApp',
  'crm-field': 'CRM field',
  'crm-opportunity': 'CRM opportunity',
  file: 'File',
  recommendation: 'Recommendation',
  none: 'Reminder',
};

/** The minimum shape a task needs for its output kind to be read. */
export interface TaskWithOutput {
  taskOutput?: { kind?: string | null } | null;
}

/** A task's output kind, or `undefined` when it has not been decided. */
export function taskOutputKind(task: TaskWithOutput): TaskOutputKind | undefined {
  const kind = task.taskOutput?.kind;
  return kind && (TASK_OUTPUT_KINDS as readonly string[]).includes(kind)
    ? (kind as TaskOutputKind)
    : undefined;
}

/** Display label for a task's output kind; `Undecided` while the output has not been chosen. */
export function taskOutputLabel(task: TaskWithOutput): string {
  const kind = taskOutputKind(task);
  return kind ? TASK_OUTPUT_KIND_LABELS[kind] : 'Undecided';
}