Halkyon's shared packages

A pub workspace of the Dart packages Halkyon's apps share: halkyon_ui,
Halkyon's look (the theme, fonts, layout and shared widgets, with texts
in English and German), halkyon_core's low-level primitives and
halkyon_interop's cross-app contracts. Dart 3.13 with LeanCode's lints,
configured once at the root; apps take a package by git, pinned to a
signed commit.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Signed-off-by: Tizian 「ティツィアーン」 <raisondetredev@pm.me>
This commit is contained in:
Tizian 「ティツィアーン」 2026-10-18 21:46:55 +02:00
commit 80fa7b9628
Signed by: raisondetredev
GPG key ID: 07F6FCF405488B64
105 changed files with 6762 additions and 0 deletions

31
packages/halkyon_core/.gitignore vendored Normal file
View file

@ -0,0 +1,31 @@
# Miscellaneous
*.class
*.log
*.pyc
*.swp
.DS_Store
.atom/
.buildlog/
.history
.svn/
migrate_working_dir/
# IntelliJ related
*.iml
*.ipr
*.iws
.idea/
# The .vscode folder contains launch configuration and tasks you configure in
# VS Code which you may wish to be included in version control, so this line
# is commented out by default.
#.vscode/
# Flutter/Dart/Pub related
# Libraries should not include pubspec.lock, per https://dart.dev/guides/libraries/private-files#pubspeclock.
/pubspec.lock
**/doc/api/
.dart_tool/
.flutter-plugins-dependencies
/build/
/coverage/

View file

@ -0,0 +1,10 @@
# This file tracks properties of this Flutter project.
# Used by Flutter tool to assess capabilities and perform upgrades etc.
#
# This file should be version controlled and should not be manually edited.
version:
revision: "cc0734ac716fbb8b90f3f9db8020958b1553afa7"
channel: "stable"
project_type: package

View file

@ -0,0 +1,3 @@
## 0.0.1
* TODO: Describe initial release.

View file

@ -0,0 +1 @@
TODO: Add your license here.

View file

@ -0,0 +1,39 @@
<!--
This README describes the package. If you publish this package to pub.dev,
this README's contents appear on the landing page for your package.
For information about how to write a good package README, see the guide for
[writing package pages](https://dart.dev/tools/pub/writing-package-pages).
For general information about developing packages, see the Dart guide for
[creating packages](https://dart.dev/guides/libraries/create-packages)
and the Flutter guide for
[developing packages and plugins](https://flutter.dev/to/develop-packages).
-->
TODO: Put a short description of the package here that helps potential users
know whether this package might be useful for them.
## Features
TODO: List what your package can do. Maybe include images, gifs, or videos.
## Getting started
TODO: List prerequisites and provide or point to information on how to
start using the package.
## Usage
TODO: Include short and useful examples for package users. Add longer examples
to `/example` folder.
```dart
const like = 'sample';
```
## Additional information
TODO: Tell users more about the package: where to find more information, how to
contribute to the package, how to file issues, what response they can expect
from the package authors, and more.

View file

@ -0,0 +1,2 @@
# The workspace's lint rules (see ../../analysis_options.yaml).
include: ../../analysis_options.yaml

View file

@ -0,0 +1,17 @@
/// Low-level primitives shared across Halkyon apps.
///
/// This package is pure Dart and has no Flutter dependency. It provides:
/// - A re-export of `package:clock`'s `Clock` for testable time access.
/// - A thin `generateUuid` wrapper for v4 UUID generation.
/// - A `Logger` interface and basic `ConsoleLogger` implementation.
/// - The optional `HalkyonException` marker interface.
library;
// Re-export the clock package directly. Halkyon apps depend on `Clock` for
// testable time access; re-exporting here means they get it via halkyon_core
// without needing a separate `clock` dependency.
export 'package:clock/clock.dart' show Clock, clock;
export 'src/exceptions.dart';
export 'src/logger.dart';
export 'src/uuid.dart';

View file

@ -0,0 +1,11 @@
/// Marker interface for exceptions originating in Halkyon code.
///
/// Implementing this is optional. It exists so callers can distinguish
/// "this came from Halkyon" from "this came from a library we use" using
/// `on HalkyonException catch (e)` if they want that granularity.
///
/// Most Halkyon exceptions should also extend a more specific type
/// (e.g., `AuthException`, `SyncException`) defined in the relevant feature.
abstract class HalkyonException() implements Exception {
String get message;
}

View file

@ -0,0 +1,54 @@
/// Severity levels for log messages.
enum LogLevel() {
debug,
info,
warning,
error,
}
/// A minimal logging interface.
///
/// Implementations are injected via the app's `Dependencies` composition root
/// rather than imported globally, so tests can swap in fakes.
abstract interface class Logger() {
void log(
LogLevel level,
String message, {
Object? error,
StackTrace? stackTrace,
});
}
/// A logger that writes to stdout. Suitable for development and tests.
///
/// Production apps should use a logger that forwards to Sentry or similar,
/// configured at the composition root.
class const ConsoleLogger() implements Logger {
@override
void log(
LogLevel level,
String message, {
Object? error,
StackTrace? stackTrace,
}) {
final prefix = switch (level) {
LogLevel.debug => '[DEBUG]',
LogLevel.info => '[INFO]',
LogLevel.warning => '[WARN]',
LogLevel.error => '[ERROR]',
};
// Writing to stdout is this logger's whole purpose.
// ignore: avoid_print
print('$prefix $message');
if (error != null) {
// As above: stdout is where this logger writes.
// ignore: avoid_print
print(' error: $error');
}
if (stackTrace != null) {
// As above: stdout is where this logger writes.
// ignore: avoid_print
print(' stack: $stackTrace');
}
}
}

View file

@ -0,0 +1,10 @@
import 'package:uuid/uuid.dart';
const _uuid = Uuid();
/// Generates a v4 (random) UUID as a lowercase hyphenated string.
///
/// Thin wrapper over `package:uuid` so Halkyon code doesn't need to import
/// it directly. If we ever need to swap the UUID library, this is the only
/// site that changes.
String generateUuid() => _uuid.v4();

View file

@ -0,0 +1,15 @@
name: halkyon_core
description: "Low-level primitives shared across Halkyon apps. Pure Dart, no Flutter."
version: 0.0.1
publish_to: none
resolution: workspace
environment:
sdk: ^3.13.0
dependencies:
clock: ^1.1.1
uuid: ^4.5.0
dev_dependencies:
test: ^1.25.0

View file

@ -0,0 +1,52 @@
import 'package:halkyon_core/halkyon_core.dart';
import 'package:test/test.dart';
void main() {
group('generateUuid', () {
test('produces a non-empty string', () {
expect(generateUuid(), isNotEmpty);
});
test('produces a valid v4 UUID format', () {
// v4 UUID: 8-4-4-4-12 hex characters, with version 4 in the third group.
final uuid = generateUuid();
expect(
uuid,
matches(
RegExp(
r'^[0-9a-f]{8}-[0-9a-f]{4}-4[0-9a-f]{3}-[89ab][0-9a-f]{3}-[0-9a-f]{12}$',
),
),
);
});
test('produces different values on successive calls', () {
final a = generateUuid();
final b = generateUuid();
expect(a, isNot(equals(b)));
});
});
group('ConsoleLogger', () {
test('can be instantiated as const', () {
const logger = ConsoleLogger();
expect(logger, isA<Logger>());
});
// Note: we don't test that ConsoleLogger actually prints, because
// capturing stdout in tests is fragile and the implementation is trivial.
// If we add structured logging later, we'll test that more carefully.
});
group('HalkyonException', () {
test('is implementable', () {
final ex = _TestException('boom');
expect(ex, isA<HalkyonException>());
expect(ex, isA<Exception>());
expect(ex.message, equals('boom'));
});
});
}
class _TestException(@override final String message)
implements HalkyonException;

31
packages/halkyon_interop/.gitignore vendored Normal file
View file

@ -0,0 +1,31 @@
# Miscellaneous
*.class
*.log
*.pyc
*.swp
.DS_Store
.atom/
.buildlog/
.history
.svn/
migrate_working_dir/
# IntelliJ related
*.iml
*.ipr
*.iws
.idea/
# The .vscode folder contains launch configuration and tasks you configure in
# VS Code which you may wish to be included in version control, so this line
# is commented out by default.
#.vscode/
# Flutter/Dart/Pub related
# Libraries should not include pubspec.lock, per https://dart.dev/guides/libraries/private-files#pubspeclock.
/pubspec.lock
**/doc/api/
.dart_tool/
.flutter-plugins-dependencies
/build/
/coverage/

View file

@ -0,0 +1,10 @@
# This file tracks properties of this Flutter project.
# Used by Flutter tool to assess capabilities and perform upgrades etc.
#
# This file should be version controlled and should not be manually edited.
version:
revision: "cc0734ac716fbb8b90f3f9db8020958b1553afa7"
channel: "stable"
project_type: package

View file

@ -0,0 +1,3 @@
## 0.0.1
* TODO: Describe initial release.

View file

@ -0,0 +1 @@
TODO: Add your license here.

View file

@ -0,0 +1,39 @@
<!--
This README describes the package. If you publish this package to pub.dev,
this README's contents appear on the landing page for your package.
For information about how to write a good package README, see the guide for
[writing package pages](https://dart.dev/tools/pub/writing-package-pages).
For general information about developing packages, see the Dart guide for
[creating packages](https://dart.dev/guides/libraries/create-packages)
and the Flutter guide for
[developing packages and plugins](https://flutter.dev/to/develop-packages).
-->
TODO: Put a short description of the package here that helps potential users
know whether this package might be useful for them.
## Features
TODO: List what your package can do. Maybe include images, gifs, or videos.
## Getting started
TODO: List prerequisites and provide or point to information on how to
start using the package.
## Usage
TODO: Include short and useful examples for package users. Add longer examples
to `/example` folder.
```dart
const like = 'sample';
```
## Additional information
TODO: Tell users more about the package: where to find more information, how to
contribute to the package, how to file issues, what response they can expect
from the package authors, and more.

View file

@ -0,0 +1,2 @@
# The workspace's lint rules (see ../../analysis_options.yaml).
include: ../../analysis_options.yaml

View file

@ -0,0 +1,13 @@
/// Cross-app interoperability contracts for the Halkyon ecosystem.
///
/// This package is pure Dart and defines:
/// - `TaskShape`: a minimal type for representing tasks across apps
/// (e.g., a Halkyon Learn review session surfaced in Halkyon ToDo).
/// - `HalkyonEvent`: a sealed class hierarchy for cross-app events.
/// - `EventPublisher`: an interface for emitting events to other apps,
/// with `DormantPublisher` as a no-op default for apps running standalone.
library;
export 'src/event_publisher.dart';
export 'src/events.dart';
export 'src/task_shape.dart';

View file

@ -0,0 +1,24 @@
import 'package:halkyon_interop/src/events.dart';
/// Publishes [HalkyonEvent]s to other Halkyon apps installed alongside this one.
///
/// The actual transport (platform channels, intents, App Group containers,
/// etc.) is implementation-specific and lives in the app's composition root,
/// not in this package.
abstract interface class EventPublisher() {
/// Publish an event. Implementations should be non-blocking and best-effort:
/// failing to deliver to peer apps must not fail the originating action.
Future<void> publish(HalkyonEvent event);
}
/// A no-op [EventPublisher] for apps running in isolation.
///
/// When a Halkyon app starts and detects no peer apps to broadcast to (or
/// when the user has disabled cross-app communication), inject this. All
/// `publish` calls are silently dropped.
class const DormantPublisher() implements EventPublisher {
@override
Future<void> publish(HalkyonEvent event) async {
// Intentionally empty. Events are dropped when there are no peers.
}
}

Some files were not shown because too many files have changed in this diff Show more