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>
This commit is contained in:
2026-06-11 12:11:53 +02:00
co-authored by Claude Opus 4.8
parent bcea5f15b7
commit 6d0ebab721
444 changed files with 7587 additions and 12849 deletions
+4 -1
View File
@@ -122,7 +122,10 @@ void main() {
d.register(
'git.checkout',
(req) async => IpcResponse.ok(id: req.id, data: const {}),
schema: CommandSchema(positional: const ['ref'], args: {'ref': ArgSpec(pattern: RegExp(r'^\w+$'))}),
schema: CommandSchema(
positional: const ['ref'],
args: {'ref': ArgSpec(pattern: RegExp(r'^\w+$'))},
),
);
final tools = d.mcpTools();
+4 -6
View File
@@ -138,9 +138,7 @@ void main() {
await call('editor.open', {'path': 'a.md'});
await call('editor.open', {'path': 'b.md'});
final r = await call('editor.list');
final names = [
for (final b in (r.data['buffers'] as List).cast<Map>()) b['path'],
];
final names = [for (final b in (r.data['buffers'] as List).cast<Map>()) b['path']];
expect(names, containsAll(['a.md', 'b.md']));
});
@@ -204,14 +202,14 @@ void main() {
test('editor.set-selection clamps and applies', () async {
await call('editor.open', {'path': 'doc.md'});
final r = await call('editor.set-selection', {
'selection': {'start': 0, 'end': 3}
'selection': {'start': 0, 'end': 3},
});
expect(r.ok, isTrue);
});
test('editor.set-selection without an id or active buffer returns not-found', () async {
final r = await call('editor.set-selection', {
'selection': {'start': 0, 'end': 1}
'selection': {'start': 0, 'end': 1},
});
expect(r.ok, isFalse);
expect(r.error!.kind, 'not_found');
@@ -226,7 +224,7 @@ void main() {
expect(read1.data['content'], 'replaced');
final r2 = await call('editor.set-content', {
'text': 'short',
'selection': {'start': 1, 'end': 99}
'selection': {'start': 1, 'end': 99},
});
expect(r2.ok, isTrue);
});
+1 -3
View File
@@ -67,9 +67,7 @@ void main() {
test('files.ls into a subdirectory returns its contents', () async {
final r = await call('files.ls', const {'path': 'lib'});
expect(r.ok, isTrue);
final names = [
for (final e in (r.data['entries'] as List).cast<Map>()) e['name'],
];
final names = [for (final e in (r.data['entries'] as List).cast<Map>()) e['name']];
expect(names, ['main.dart']);
});
+4 -4
View File
@@ -40,8 +40,8 @@ void main() {
(
'git.stage',
const {
'paths': ['file.txt']
}
'paths': ['file.txt'],
},
),
('git.stage-all', const <String, Object?>{}),
('git.unstage', const <String, Object?>{}),
@@ -53,8 +53,8 @@ void main() {
(
'git.discard',
const {
'paths': ['file.txt']
}
'paths': ['file.txt'],
},
),
('git.commit', const {'message': 'hi'}),
('git.stash', const <String, Object?>{}),
+12 -27
View File
@@ -13,23 +13,11 @@ void main() {
setUp(() async {
sandbox = await Directory.systemTemp.createTemp('clide-git-cmd-test-');
await Process.run('git', ['init'], workingDirectory: sandbox.path);
await Process.run(
'git',
['config', 'user.email', 'test@test.com'],
workingDirectory: sandbox.path,
);
await Process.run(
'git',
['config', 'user.name', 'Test'],
workingDirectory: sandbox.path,
);
await Process.run('git', ['config', 'user.email', 'test@test.com'], workingDirectory: sandbox.path);
await Process.run('git', ['config', 'user.name', 'Test'], workingDirectory: sandbox.path);
await File('${sandbox.path}/file.txt').writeAsString('hello\n');
await Process.run('git', ['add', '.'], workingDirectory: sandbox.path);
await Process.run(
'git',
['commit', '-m', 'init'],
workingDirectory: sandbox.path,
);
await Process.run('git', ['commit', '-m', 'init'], workingDirectory: sandbox.path);
sink = RecordingEventSink();
dispatcher = DaemonDispatcher();
@@ -64,7 +52,7 @@ void main() {
test('git.stage + git.status shows staged file', () async {
await File('${sandbox.path}/new.txt').writeAsString('x');
final stage = await call('git.stage', {
'paths': ['new.txt']
'paths': ['new.txt'],
});
expect(stage.ok, isTrue);
@@ -82,10 +70,10 @@ void main() {
test('git.unstage removes from staging', () async {
await File('${sandbox.path}/new.txt').writeAsString('x');
await call('git.stage', {
'paths': ['new.txt']
'paths': ['new.txt'],
});
final unstage = await call('git.unstage', {
'paths': ['new.txt']
'paths': ['new.txt'],
});
expect(unstage.ok, isTrue);
@@ -97,7 +85,7 @@ void main() {
test('git.commit creates a commit', () async {
await File('${sandbox.path}/c.txt').writeAsString('x');
await call('git.stage', {
'paths': ['c.txt']
'paths': ['c.txt'],
});
final r = await call('git.commit', {'message': 'test commit'});
expect(r.ok, isTrue);
@@ -121,7 +109,7 @@ void main() {
test('git.diff --staged returns staged diffs', () async {
await File('${sandbox.path}/file.txt').writeAsString('modified\n');
await call('git.stage', {
'paths': ['file.txt']
'paths': ['file.txt'],
});
final r = await call('git.diff', {'staged': true});
expect(r.ok, isTrue);
@@ -139,7 +127,7 @@ void main() {
test('git.discard restores a file', () async {
await File('${sandbox.path}/file.txt').writeAsString('changed');
final r = await call('git.discard', {
'paths': ['file.txt']
'paths': ['file.txt'],
});
expect(r.ok, isTrue);
final content = await File('${sandbox.path}/file.txt').readAsString();
@@ -155,12 +143,9 @@ void main() {
test('mutations emit git.changed events', () async {
await File('${sandbox.path}/e.txt').writeAsString('x');
await call('git.stage', {
'paths': ['e.txt']
'paths': ['e.txt'],
});
expect(
sink.events,
contains(predicate<IpcEvent>((e) => e.kind == 'git.changed')),
);
expect(sink.events, contains(predicate<IpcEvent>((e) => e.kind == 'git.changed')));
});
test('git.stage-all stages everything', () async {
@@ -192,7 +177,7 @@ void main() {
await File('${sandbox.path}/file.txt').writeAsString('hello\nworld\n');
await File('${sandbox.path}/other.txt').writeAsString('o');
final r = await call('git.diff', {
'paths': ['file.txt']
'paths': ['file.txt'],
});
expect(r.ok, isTrue);
final diffs = r.data['diffs'] as List;
+6 -11
View File
@@ -17,19 +17,14 @@ void main() {
void wire({bool liveUi = true, Set<String> found = const {'docs/diagram.png'}, bool withResolver = true}) {
published = [];
d = DaemonDispatcher();
registerImageCommands(
d,
() {
if (!liveUi) return null;
return (publisher, channel, data) => published.add((publisher: publisher, channel: channel, data: data));
},
resolve: withResolver ? (path) => found.contains(path) ? '/abs/$path' : null : null,
);
registerImageCommands(d, () {
if (!liveUi) return null;
return (publisher, channel, data) => published.add((publisher: publisher, channel: channel, data: data));
}, resolve: withResolver ? (path) => found.contains(path) ? '/abs/$path' : null : null);
}
Future<IpcResponse> show(List<String> positional, {Map<String, Object?>? flags}) => d.dispatch(
IpcRequest(id: '1', cmd: 'image.show', args: {'positional': positional, if (flags != null) 'flags': flags}),
);
Future<IpcResponse> show(List<String> positional, {Map<String, Object?>? flags}) =>
d.dispatch(IpcRequest(id: '1', cmd: 'image.show', args: {'positional': positional, 'flags': ?flags}));
test('resolves a workspace-relative path and publishes an image message', () async {
wire();
+3 -6
View File
@@ -75,10 +75,7 @@ void main() {
expect(viaText.ok, isTrue);
expect(viaText.data['written'], greaterThan(0));
final viaBase64 = await call('pane.write', {
'id': id,
'bytes_b64': base64Encode(utf8.encode('def')),
});
final viaBase64 = await call('pane.write', {'id': id, 'bytes_b64': base64Encode(utf8.encode('def'))});
expect(viaBase64.ok, isTrue);
});
@@ -115,7 +112,7 @@ void main() {
test('pane.spawn rejects non-string argv entries', () async {
final r = await call('pane.spawn', const {
'argv': ['/bin/sh', 42]
'argv': ['/bin/sh', 42],
});
expect(r.ok, isFalse);
expect(r.error!.message, contains('strings'));
@@ -262,7 +259,7 @@ void main() {
test('merges PTY panes and UI tabs in one list', () async {
await call('pane.spawn', {
'argv': const ['/bin/cat']
'argv': const ['/bin/cat'],
});
final r = await call('pane.list', const {});
final panes = (r.data['panes'] as List).cast<Map>();
+1 -4
View File
@@ -17,10 +17,7 @@ void main() {
late _FakeResizer resizer;
setUp(() {
resizer = _FakeResizer(
slots: {'sidebar': 200, 'context': 240, 'workspace': 800},
editorRatio: 0.35,
);
resizer = _FakeResizer(slots: {'sidebar': 200, 'context': 240, 'workspace': 800}, editorRatio: 0.35);
dispatcher = DaemonDispatcher();
registerPanelCommands(dispatcher, resizer);
});
+1 -1
View File
@@ -49,7 +49,7 @@ void main() {
const {
'ids': ['T-1'],
'status': 'done',
}
},
),
('pql.tickets.board', const <String, Object?>{}),
('pql.plan.status', const <String, Object?>{}),
+3 -16
View File
@@ -181,11 +181,7 @@ void main() {
});
test('pql.decisions.show forwards withRefs / withTickets', () async {
final r = await call('pql.decisions.show', {
'id': 'D-1',
'withRefs': true,
'withTickets': true,
});
final r = await call('pql.decisions.show', {'id': 'D-1', 'withRefs': true, 'withTickets': true});
expect(r.ok, isTrue);
expect(r.data['id'], 'D-1');
});
@@ -198,12 +194,7 @@ void main() {
});
test('pql.tickets.list with filters narrows + shows status', () async {
final r = await call('pql.tickets.list', {
'status': 'done',
'team': 'whatever',
'assigned': 'no-one',
'decision': 'D-1',
});
final r = await call('pql.tickets.list', {'status': 'done', 'team': 'whatever', 'assigned': 'no-one', 'decision': 'D-1'});
expect(r.ok, isTrue);
expect(r.data['tickets'], isA<List>());
});
@@ -212,11 +203,7 @@ void main() {
final missing = await call('pql.tickets.show');
expect(missing.ok, isFalse);
expect(missing.error!.kind, 'user_error');
final ok = await call('pql.tickets.show', {
'id': 'T-1',
'withContext': true,
'withBlockers': true,
});
final ok = await call('pql.tickets.show', {'id': 'T-1', 'withContext': true, 'withBlockers': true});
expect(ok.ok, isTrue);
});
+1 -6
View File
@@ -17,12 +17,7 @@ void main() {
File('${dir.path}/a.dart').writeAsStringSync('final answer = 42;\n');
File('${dir.path}/b.dart').writeAsStringSync('// no hits here\n');
sink = RecordingEventSink();
final service = SearchService(
root: dir,
ignore: IgnoreSet([]),
events: sink,
useIsolates: false,
);
final service = SearchService(root: dir, ignore: IgnoreSet([]), events: sink, useIsolates: false);
d = DaemonDispatcher();
registerSearchCommands(d, service);
});
+1 -7
View File
@@ -13,13 +13,7 @@ void main() {
test('status resolves and returns the assembled snapshot with exit 0', () async {
final d = DaemonDispatcher();
registerStatusCommand(
d,
() async => {
'workspace': '/repo',
'focusedFile': null,
'panes': const [],
});
registerStatusCommand(d, () async => {'workspace': '/repo', 'focusedFile': null, 'panes': const []});
final r = await d.dispatch(req());
expect(r.ok, isTrue);
expect(r.data['workspace'], '/repo');
+8 -17
View File
@@ -20,19 +20,13 @@ void main() {
published = [];
filterValues = {};
d = DaemonDispatcher();
registerUiCommands(
d,
() {
if (!liveUi) return null;
return (publisher, channel, data) => published.add((publisher: publisher, channel: channel, data: data));
},
filterValue: liveUi ? (address) => filterValues[address] : null,
);
registerUiCommands(d, () {
if (!liveUi) return null;
return (publisher, channel, data) => published.add((publisher: publisher, channel: channel, data: data));
}, filterValue: liveUi ? (address) => filterValues[address] : null);
}
Future<IpcResponse> open(List<String> positional) => d.dispatch(
IpcRequest(id: '1', cmd: 'ui.open', args: {'positional': positional}),
);
Future<IpcResponse> open(List<String> positional) => d.dispatch(IpcRequest(id: '1', cmd: 'ui.open', args: {'positional': positional}));
test('ui open tickets T-48 publishes a tickets selection', () async {
wire();
@@ -97,9 +91,8 @@ void main() {
// -- ui.toast (T-50 drive-half) -------------------------------------------
Future<IpcResponse> toast(List<String> positional, {Map<String, Object?>? flags}) => d.dispatch(
IpcRequest(id: '1', cmd: 'ui.toast', args: {'positional': positional, if (flags != null) 'flags': flags}),
);
Future<IpcResponse> toast(List<String> positional, {Map<String, Object?>? flags}) =>
d.dispatch(IpcRequest(id: '1', cmd: 'ui.toast', args: {'positional': positional, 'flags': ?flags}));
test('ui toast publishes a toast message (default info severity)', () async {
wire();
@@ -150,9 +143,7 @@ void main() {
// -- ui.filter (T-270 drive+observe half) ---------------------------------
Future<IpcResponse> filter(List<String> positional) => d.dispatch(
IpcRequest(id: '1', cmd: 'ui.filter', args: {'positional': positional}),
);
Future<IpcResponse> filter(List<String> positional) => d.dispatch(IpcRequest(id: '1', cmd: 'ui.filter', args: {'positional': positional}));
test('ui filter <address> <text> publishes a filter.set', () async {
wire();