| 367 | const result = childProcess.spawnSync('git', ['status', '--short'], { |
| 368 | cwd: projectRoot, |
| 369 | encoding: 'utf8', |
| 370 | stdio: ['ignore', 'pipe', 'ignore'], |
| 371 | }); |
| 372 | if (result.status !== 0) return false; |
| 373 | return Boolean(String(result.stdout || '').trim()); |
| 374 | } |
| 375 | |
| 376 | function boundaryFor(route, dirty) { |
| 377 | if (dirty && route !== '/dashboard' && route !== '/do operator') { |
| 378 | return { |
| 379 | canRunNow: false, |
| 380 | boundary: 'worktree-review', |
| 381 | risk: 'low', |
| 382 | approval: 'Review uncommitted worktree changes before starting the routed action.', |
| 383 | }; |
| 384 | } |
| 385 | if (route === '/fleet --quick') { |
| 386 | return { |
| 387 | canRunNow: false, |
| 388 | boundary: 'parallel-agent-approval', |
| 389 | risk: 'medium-high', |
| 390 | approval: 'Approve Fleet only after scopes are independent and merge order is clear.', |
| 391 | }; |
| 392 | } |
| 393 | if (route === '/archon') { |
| 394 | return { |
| 395 | canRunNow: false, |
| 396 | boundary: 'campaign-approval', |
| 397 | risk: 'medium', |
| 398 | approval: 'Approve campaign persistence after phases and exit evidence are clear.', |
| 399 | }; |
| 400 | } |
| 401 | return { |
| 402 | canRunNow: true, |
| 403 | boundary: route.startsWith('/') ? 'agent-route' : 'local-command', |