(_input, { getAppState, options })
| 193 | return true |
| 194 | }, |
| 195 | async validateInput(_input, { getAppState, options }) { |
| 196 | // Teammate AppState may show leader's mode (runAgent.ts skips override in |
| 197 | // acceptEdits/bypassPermissions/auto); isPlanModeRequired() is the real source |
| 198 | if (isTeammate()) { |
| 199 | return { result: true } |
| 200 | } |
| 201 | // The deferred-tool list announces this tool regardless of mode, so the |
| 202 | // model can call it after plan approval (fresh delta on compact/clear). |
| 203 | // Reject before checkPermissions to avoid showing the approval dialog. |
| 204 | const mode = getAppState().toolPermissionContext.mode |
| 205 | if (mode !== 'plan') { |
| 206 | logEvent('tengu_exit_plan_mode_called_outside_plan', { |
| 207 | model: |
| 208 | options.mainLoopModel as AnalyticsMetadata_I_VERIFIED_THIS_IS_NOT_CODE_OR_FILEPATHS, |
| 209 | mode: mode as AnalyticsMetadata_I_VERIFIED_THIS_IS_NOT_CODE_OR_FILEPATHS, |
| 210 | hasExitedPlanModeInSession: hasExitedPlanModeInSession(), |
| 211 | }) |
| 212 | return { |
| 213 | result: false, |
| 214 | message: |
| 215 | 'You are not in plan mode. This tool is only for exiting plan mode after writing a plan. If your plan was already approved, continue with implementation.', |
| 216 | errorCode: 1, |
| 217 | } |
| 218 | } |
| 219 | return { result: true } |
| 220 | }, |
| 221 | async checkPermissions(input, context) { |
| 222 | // For ALL teammates, bypass the permission UI to avoid sending permission_request |
| 223 | // The call() method handles the appropriate behavior: |
nothing calls this directly
no test coverage detected