Files
clide/lib/builtin/claude/src/ticket_pick_up.dart
T
jpmschweitzerandClaude Opus 4.8 6d0ebab721 chore: adopt Dart 3.9 toolchain — honest floor + tall-style reformat (T-353)
Raise the declared minimums in pubspec.yaml to what our deps already
require: Flutter >=3.35.0 / Dart >=3.9.0 (was 3.19.0 / 3.5.0). alchemist
0.12 needs Flutter 3.32; Dart 3.9 first ships in Flutter 3.35, so 3.35 is
the binding floor. Pin the exact build toolchain in .fvmrc (Flutter
3.44.1).

Moving to the Dart 3.9 language level switches `dart format` to the new
"tall" style and enables two new lints. This commit is the resulting
mechanical churn, isolated from any behaviour change:
  - whole-tree `dart format` reformat (tall style)
  - `dart fix` for unnecessary_underscores + use_null_aware_elements

No runtime behaviour change; `make test` green.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-06-11 12:11:53 +02:00

50 lines
2.0 KiB
Dart

/// Sidebar "pick up" handling (T-327/T-339): inject a ticket's prompt into the
/// active Claude session and, on acceptance, advance the ticket to in_progress.
///
/// Kept out of `extension.dart` so it's unit-testable without dragging the whole
/// (UI-wiring) extension into instrumentation.
library;
import 'package:clide/builtin/claude/src/session_orchestrator.dart';
import 'package:clide/kernel/kernel.dart';
/// Statuses a pick-up may advance from: a not-yet-started ticket. Picking up a
/// ticket that's already `in_progress`/`review`/`done`/`cancelled` injects the
/// prompt but leaves the status alone, so a re-pick-up never drags it backwards
/// or reopens it (T-339).
const kPickUpStartableStatuses = {'backlog', 'ready'};
/// Inject a picked-up ticket's prompt into the active session (the `primary`
/// lead, else the first visible one) and, on acceptance from a not-yet-started
/// ticket, advance it to `in_progress` and publish a `changed` so the sidebar
/// refreshes (T-327/T-339). Returns whether a live session accepted the prompt.
///
/// With no live session there's no injection and no state change — a quiet
/// no-op.
Future<bool> applyTicketPickUp(
Map<String, Object?> data, {
required ClaudeSessionOrchestrator? orchestrator,
required DaemonClient ipc,
required MessageBus messages,
}) async {
final prompt = data['prompt'] as String?;
if (prompt == null || prompt.isEmpty) return false;
final target = orchestrator?.byId('primary') ?? orchestrator?.visibleSessions.firstOrNull;
if (target == null) return false; // no live session → quiet no-op, no state change
orchestrator!.injectMessage(target.id, prompt);
final id = data['id'] as String?;
final status = data['status'] as String?;
if (id != null && id.isNotEmpty && kPickUpStartableStatuses.contains(status)) {
final resp = await ipc.request(
'pql.tickets.status',
args: {
'ids': [id],
'status': 'in_progress',
},
);
if (resp.ok) messages.publish('builtin.tickets', 'changed', {'id': id});
}
return true;
}