{"version":3,"file":"index.mjs","names":[],"sources":["../../../../src/services/taskResult/index.ts"],"sourcesContent":["import type {\n  AssignmentSummary,\n  Task,\n  TaskAction,\n  TaskDetails,\n  TaskDocument,\n  TaskMutationParams,\n  UpsertItemOutcome,\n} from '../../models/task';\nimport { deriveBlocks, isTaskListComplete } from '../../models/taskGraph';\nimport type { Op } from '../reducer';\n\nexport const MSG_ALL_COMPLETE_CLEAR =\n  'All tasks are completed. Review the full task list once more, then close it with task {\"action\":\"clear\"}.';\n\n/**\n * Steering for a mixed batch. Unlike a batch of spawned subagents, a failed\n * entry here had no side effect at all, so retrying the failures is the safe\n * move and the model must be told so or it will do nothing. The hazard is the\n * other half: resending an applied create would make a second task.\n */\nexport const MSG_UPSERT_PARTIAL =\n  'The applied entries are committed. Resend only the failed entries, corrected — a failed entry changed nothing, so a corrected retry is safe. Do not resend an entry that already applied: an entry without an id creates a second task.';\n\nexport const MSG_UPSERT_NONE_APPLIED = 'No task changed, so the whole call can be resent once corrected.';\n\nexport const MSG_ASSIGN_PARTIAL =\n  'Successful assignments are already running. Retry only the failed entries after correcting their task state or arguments; do not resend successful entries.';\n\nexport interface AssignmentItemResult {\n  index: number;\n  id: number;\n  agent: string;\n  ok: boolean;\n  message: string;\n}\n\n/** LLM-facing report for a native assignment batch. */\nexport function formatAssignmentResults(items: readonly AssignmentItemResult[]): string {\n  if (items.length === 1) return items[0].message;\n\n  const succeeded = items.filter((item) => item.ok).length;\n  const failed = items.length - succeeded;\n  const lines = [\n    `Assigned ${succeeded}/${items.length} tasks${failed > 0 ? `; ${failed} failed` : ''}.`,\n    ...items.map((item) =>\n      item.ok\n        ? `- [${item.index}] Delegated #${item.id} to ${item.agent}`\n        : `- [${item.index}] Failed #${item.id} → ${item.agent}: ${item.message}`,\n    ),\n  ];\n\n  if (failed > 0 && succeeded > 0) lines.push('', MSG_ASSIGN_PARTIAL);\n  if (failed === 0) {\n    lines.push(\n      '',\n      'All assignments are running independently in the background. Continue non-overlapping work, or end your turn.',\n    );\n  }\n  return lines.join('\\n');\n}\n\n/** `[status] #id subject (activeForm) [agent] ⛓ #dep` — the `list` line format. */\nfunction formatListLine(task: Task): string {\n  const block = task.blockedBy?.length ? ` ⛓ ${task.blockedBy.map((id) => `#${id}`).join(',')}` : '';\n  const form = task.status === 'in_progress' && task.activeForm ? ` (${task.activeForm})` : '';\n  const delegated = task.delegation && task.delegation.state !== 'cancelled' ? ` [${task.delegation.agent}]` : '';\n  return `[${task.status}] #${task.id} ${task.subject}${form}${delegated}${block}`;\n}\n\nfunction formatDelegationLines(task: Task): string[] {\n  const delegation = task.delegation;\n  if (!delegation) return [];\n\n  const lines = [`  delegated to: ${delegation.agent} (${delegation.state})`];\n  if (delegation.model) lines.push(`  model: ${delegation.model}`);\n  if (delegation.result?.error) lines.push(`  error: ${delegation.result.error}`);\n  if (delegation.result?.outputPath) lines.push(`  output file: ${delegation.result.outputPath}`);\n  if (delegation.result?.output) lines.push(`  output: ${delegation.result.output}`);\n  return lines;\n}\n\nfunction formatGetLines(task: Task, document: TaskDocument): string {\n  const blocks = deriveBlocks(document.tasks).get(task.id) ?? [];\n  const lines = [`#${task.id} [${task.status}] ${task.subject}`];\n  if (task.description) lines.push(`  description: ${task.description}`);\n  if (task.activeForm) lines.push(`  activeForm: ${task.activeForm}`);\n  if (task.blockedBy?.length) lines.push(`  blockedBy: ${task.blockedBy.map((id) => `#${id}`).join(', ')}`);\n  if (blocks.length) lines.push(`  blocks: ${blocks.map((id) => `#${id}`).join(', ')}`);\n  if (task.owner) lines.push(`  owner: ${task.owner}`);\n  lines.push(...formatDelegationLines(task));\n  return lines.join('\\n');\n}\n\n/** One entry's outcome. Batch lines prefix this with `- [n] `. */\nfunction formatUpsertItem(item: UpsertItemOutcome): string {\n  switch (item.kind) {\n    case 'created': {\n      const ref = item.ref ? ` (ref \"${item.ref}\")` : '';\n      const deps = item.blockedBy?.length ? ` — blocked by ${item.blockedBy.map((id) => `#${id}`).join(', ')}` : '';\n      return `Created #${item.id}${ref}: ${item.subject} (${item.status})${deps}`;\n    }\n    case 'updated': {\n      const transition = item.fromStatus === item.toStatus ? '' : ` (${item.fromStatus} -> ${item.toStatus})`;\n      return `Updated #${item.id}${transition}`;\n    }\n    case 'unchanged':\n      return `No change: #${item.id} already matches the requested values (status: ${item.status})`;\n    case 'failed':\n      return `Failed${item.id === undefined ? '' : ` #${item.id}`}: ${item.message}`;\n  }\n}\n\n/**\n * The thrown message when an upsert applied nothing. Kept separate from\n * `formatContent` because the caller wraps it in the actionable Options block\n * rather than returning it as a successful result.\n */\nexport function formatUpsertFailureText(op: Extract<Op, { kind: 'upsert' }>): string {\n  if (op.items.length === 1) return op.items[0].kind === 'failed' ? op.items[0].message : 'no entry was applied';\n  return [\n    'no entry was applied.',\n    ...op.items.map((item) => `- [${item.index}] ${formatUpsertItem(item)}`),\n    MSG_UPSERT_NONE_APPLIED,\n  ].join('\\n');\n}\n\n/**\n * Pure formatter: `(op, document) -> string`. The switch is closed over `Op`,\n * so a new reducer variant fails to compile until it is handled here.\n */\nexport function formatContent(op: Op, document: TaskDocument): string {\n  switch (op.kind) {\n    case 'upsert': {\n      // A batch of one is the common case and must not read like a bulk\n      // report, so it keeps the exact single-line shape it has always had.\n      const lines =\n        op.items.length === 1\n          ? [formatUpsertItem(op.items[0])]\n          : [\n              `Upsert applied ${op.applied}/${op.items.length} entries${op.failed > 0 ? `; ${op.failed} failed` : ''}.`,\n              ...op.items.map((item) => `- [${item.index}] ${formatUpsertItem(item)}`),\n              ...(op.failed > 0 ? ['', MSG_UPSERT_PARTIAL] : []),\n            ];\n      // Once, last, and only when something landed: emitting it per entry\n      // would repeat it for every completion in a batch.\n      if (op.applied > 0 && isTaskListComplete(document.tasks)) lines.push(MSG_ALL_COMPLETE_CLEAR);\n      return lines.join('\\n');\n    }\n    case 'delete':\n      return `Deleted #${op.id}: ${op.subject}`;\n    case 'clear':\n      return `Closed task list (cleared ${op.count} tasks)`;\n    case 'list': {\n      let view = document.tasks;\n      if (!op.includeDeleted) view = view.filter((task) => task.status !== 'deleted');\n      if (op.statusFilter) view = view.filter((task) => task.status === op.statusFilter);\n      return view.length === 0 ? 'No tasks' : view.map(formatListLine).join('\\n');\n    }\n    case 'get':\n      return formatGetLines(op.task, document);\n    case 'error':\n      return `Error: ${op.message}`;\n  }\n}\n\nexport interface ToolResult {\n  content: Array<{ type: 'text'; text: string }>;\n  details: TaskDetails;\n}\n\n/** Build the LLM-facing envelope. `details` carries the post-mutation snapshot. */\nexport function buildToolResult(\n  action: TaskAction,\n  params: TaskMutationParams,\n  document: TaskDocument,\n  op: Op,\n): ToolResult {\n  return {\n    content: [{ type: 'text', text: formatContent(op, document) }],\n    details: {\n      action,\n      params: params as Record<string, unknown>,\n      tasks: document.tasks,\n      nextId: document.nextId,\n      rev: document.rev,\n      ...(op.kind === 'error' ? { error: op.message } : {}),\n      // Deliberately no `error` on a partial success: renderResult treats\n      // `details.error` as total failure and would hide the rows for the\n      // entries that did land.\n      ...(op.kind === 'upsert'\n        ? {\n            upsert: {\n              applied: op.items.flatMap((item) => (item.kind === 'failed' ? [] : [item.id])),\n              failed: op.failed,\n            },\n          }\n        : {}),\n    },\n  };\n}\n\n/** Envelope for a native assignment batch, including ids used by the consolidated TUI result. */\nexport function buildAssignmentResult(\n  params: TaskMutationParams,\n  document: TaskDocument,\n  text: string,\n  assignment: AssignmentSummary,\n): ToolResult {\n  return {\n    content: [{ type: 'text', text }],\n    details: {\n      action: 'assign',\n      params: params as Record<string, unknown>,\n      tasks: document.tasks,\n      nextId: document.nextId,\n      rev: document.rev,\n      assignment,\n    },\n  };\n}\n\n/** Envelope for delegation actions, which do not flow through the reducer. */\nexport function buildTextResult(\n  action: TaskAction,\n  params: TaskMutationParams,\n  document: TaskDocument,\n  text: string,\n  error?: string,\n): ToolResult {\n  return {\n    content: [{ type: 'text', text: error ? `Error: ${error}` : text }],\n    details: {\n      action,\n      params: params as Record<string, unknown>,\n      tasks: document.tasks,\n      nextId: document.nextId,\n      rev: document.rev,\n      ...(error ? { error } : {}),\n    },\n  };\n}\n"],"mappings":"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"}