| 152 | } |
| 153 | |
| 154 | function parseNextGoalCommand(tokens: readonly string[]): ParsedGoalCommand { |
| 155 | if (tokens.length === 2 && tokens[1] === 'manage') return { kind: 'next-manage' }; |
| 156 | let index = 1; |
| 157 | if (tokens[index] === '--') index += 1; |
| 158 | const objective = tokens.slice(index).join(' ').trim(); |
| 159 | if (objective.length === 0) { |
| 160 | return { |
| 161 | kind: 'error', |
| 162 | severity: 'hint', |
| 163 | message: |
| 164 | 'Provide an upcoming goal objective, e.g. `/goal next Ship feature X`, or use `/goal next manage`.', |
| 165 | }; |
| 166 | } |
| 167 | if (objective.length > MAX_GOAL_OBJECTIVE_LENGTH) { |
| 168 | return { |
| 169 | kind: 'error', |
| 170 | message: `Goal objective is too long (max ${MAX_GOAL_OBJECTIVE_LENGTH} characters). Reference long details by file path.`, |
| 171 | }; |
| 172 | } |
| 173 | return { kind: 'next-add', objective }; |
| 174 | } |
| 175 | |
| 176 | async function queueNextGoal( |
| 177 | host: SlashCommandHost, |