(name: string, arg?: string)
| 366 | // and return a CommandDispatchResponse (`type:'exec'` + human-readable output |
| 367 | // the app prints). Unknown commands report that they aren't wired yet. |
| 368 | private async dispatchSlash(name: string, arg?: string): Promise<{ output: string; type: string }> { |
| 369 | const out = (output: string) => ({ output, type: 'exec' }) |
| 370 | switch (name) { |
| 371 | case 'clear': |
| 372 | await this.controlQuery('clear', {}) |
| 373 | return out('Conversation cleared.') |
| 374 | case 'compact': { |
| 375 | const r = (await this.controlQuery('compact', { instructions: arg ?? null })) as any |
| 376 | return out(`Compacted${r?.tokens_saved ? ` (saved ~${r.tokens_saved} tokens)` : ''}.`) |
| 377 | } |
| 378 | case 'context': { |
| 379 | const r = (await this.controlQuery('get_context_usage', {})) as any |
| 380 | const pct = r?.percentage == null ? '?' : Math.round(r.percentage) |
| 381 | return out(`Context: ${r?.total_tokens ?? '?'}/${r?.max_tokens ?? '?'} tokens (${pct}%).`) |
| 382 | } |
| 383 | case 'effort': { |
| 384 | const r = (await this.controlQuery('set_effort', { effort: arg ?? null })) as any |
| 385 | return out(`Effort: ${r?.effort ?? arg ?? '(unchanged)'}.`) |
| 386 | } |
| 387 | case 'mode': |
| 388 | await this.controlQuery('set_permission_mode', { mode: arg }) |
| 389 | return out(`Permission mode: ${arg ?? '(unchanged)'}.`) |
| 390 | case 'model': |
| 391 | await this.controlQuery('set_model', { model: arg }) |
| 392 | return out(`Model set to ${arg ?? '(unchanged)'}.`) |
| 393 | case 'provider': { |
| 394 | const r = (await this.controlQuery('set_provider', { provider: arg })) as any |
| 395 | return out(`Provider: ${r?.provider ?? arg ?? '(unchanged)'}${r?.model ? ` (model ${r.model})` : ''}.`) |
| 396 | } |
| 397 | case 'rewind': { |
| 398 | const r = (await this.controlQuery('rewind', { turns: arg ? Number(arg) || 1 : 1 })) as any |
| 399 | return out(`Rewound ${r?.removed ?? 0} turn(s).`) |
| 400 | } |
| 401 | case 'thinking': { |
| 402 | const r = (await this.controlQuery('set_thinking', { action: arg ?? 'toggle' })) as any |
| 403 | return out(`Thinking ${r?.thinking ? 'on' : 'off'}.`) |
| 404 | } |
| 405 | case 'bg': { |
| 406 | if (arg) { |
| 407 | const r = (await this.controlQuery('bg_agent', { command: arg })) as any |
| 408 | return out(`Started background agent ${r?.id ?? ''}.`) |
| 409 | } |
| 410 | const r = (await this.controlQuery('bg_list', {})) as any |
| 411 | const tasks = Array.isArray(r?.tasks) ? r.tasks : [] |
| 412 | return out(tasks.length ? tasks.map((t: any) => `${t.id} [${t.status}] ${t.command}`).join('\n') : 'No background tasks.') |
| 413 | } |
| 414 | case 'insights': { |
| 415 | const r = (await this.controlQuery('insights', {})) as any |
| 416 | return out(r?.insights ? String(r.insights) : 'No insights available.') |
| 417 | } |
| 418 | case 'knowledge': { |
| 419 | const r = (await this.controlQuery('knowledge', { action: arg || 'status' })) as any |
| 420 | const bits = [ |
| 421 | r?.enabled != null ? `enabled=${r.enabled}` : '', |
| 422 | r?.semantic != null ? `semantic=${r.semantic}` : '' |
| 423 | ].filter(Boolean) |
| 424 | return out(`Knowledge ${bits.join(' ') || safeJson(r ?? {})}`) |
| 425 | } |
no test coverage detected