Monorepo with centralized build props, npm workspaces, LlamaSharp AI, SQLite/SQLCipher storage, Svelte frontend, and unified smoke tests. Co-Authored-By: Oz <oz-agent@warp.dev>
199 lines
6.5 KiB
C#
199 lines
6.5 KiB
C#
internal static partial class Program
|
|
{
|
|
static FragmentService NewService()
|
|
{
|
|
var config = NewConfigService();
|
|
var dbService = new JournalDatabaseService(config);
|
|
var session = new DatabaseSessionService(dbService);
|
|
session.SetPassword("smoke-test-password");
|
|
var repo = new SqliteFragmentRepository(session);
|
|
return new FragmentService(repo);
|
|
}
|
|
|
|
static Entry NewEntry(bool unlocked = true, string password = "vault-pass-123", string? root = null)
|
|
{
|
|
var config = NewConfigService(root);
|
|
var dbService = new JournalDatabaseService(config);
|
|
var session = new DatabaseSessionService(dbService);
|
|
if (unlocked)
|
|
session.SetPassword(password);
|
|
|
|
var entryRepo = new SqliteEntryFileRepository(session);
|
|
|
|
return new Entry(
|
|
NewService(),
|
|
new EntrySearchService(entryRepo),
|
|
new VaultStorageService(new VaultCryptoService(), dbService),
|
|
dbService,
|
|
session,
|
|
config,
|
|
new DisabledAiService("none"),
|
|
new DisabledSpeechBridgeService("none"),
|
|
new DisabledS2TService(),
|
|
new EntryFileService(entryRepo),
|
|
new ListService(new SqliteListRepository(session)),
|
|
new TodoService(new SqliteTodoRepository(session)),
|
|
new DisabledCoachService(),
|
|
new ConversationService(new SqliteConversationRepository(session)),
|
|
new CommandLogger());
|
|
}
|
|
|
|
static Entry NewLockedEntry() => NewEntry(unlocked: false);
|
|
|
|
static IJournalDatabaseService NewDatabaseService() => new JournalDatabaseService(NewConfigService());
|
|
|
|
static IJournalConfigService NewConfigService(string? root = null, string? databaseFilename = null)
|
|
{
|
|
var baseConfig = new JournalConfigService().Current;
|
|
var normalizedRoot = Path.GetFullPath(root ?? Path.Combine(Path.GetTempPath(), "journal-smoke", Guid.NewGuid().ToString("N")));
|
|
var appDirectory = Path.Combine(normalizedRoot, "journal");
|
|
var vaultDirectory = Path.Combine(appDirectory, "vault");
|
|
var logDirectory = Path.Combine(normalizedRoot, "logs");
|
|
|
|
Directory.CreateDirectory(vaultDirectory);
|
|
Directory.CreateDirectory(logDirectory);
|
|
|
|
var config = baseConfig with
|
|
{
|
|
ProjectRoot = normalizedRoot,
|
|
AppDirectory = appDirectory,
|
|
VaultDirectory = vaultDirectory,
|
|
LogDirectory = logDirectory,
|
|
PidFile = Path.Combine(logDirectory, "nicegui_server.pid"),
|
|
ServerControlFile = Path.Combine(logDirectory, "server_control.action"),
|
|
DatabaseFilename = databaseFilename ?? "journal_cache.db"
|
|
};
|
|
|
|
return new FixedConfigService(config);
|
|
}
|
|
|
|
private sealed class FixedConfigService(JournalConfig config) : IJournalConfigService
|
|
{
|
|
public JournalConfig Current => config;
|
|
}
|
|
|
|
static Dictionary<string, string> ReadVaultEntryTexts(string vaultPath, string password)
|
|
{
|
|
var crypto = new VaultCryptoService();
|
|
var encrypted = File.ReadAllBytes(vaultPath);
|
|
var zipBytes = crypto.DecryptData(encrypted, password);
|
|
|
|
using var stream = new MemoryStream(zipBytes);
|
|
using var archive = new ZipArchive(stream, ZipArchiveMode.Read);
|
|
var result = new Dictionary<string, string>(StringComparer.Ordinal);
|
|
foreach (var entry in archive.Entries)
|
|
{
|
|
if (string.IsNullOrEmpty(entry.Name))
|
|
continue;
|
|
|
|
using var reader = new StreamReader(entry.Open());
|
|
result[entry.Name] = reader.ReadToEnd();
|
|
}
|
|
|
|
return result;
|
|
}
|
|
|
|
static byte[] CreateZipBytes(Dictionary<string, string> files)
|
|
{
|
|
using var stream = new MemoryStream();
|
|
using (var archive = new ZipArchive(stream, ZipArchiveMode.Create, leaveOpen: true))
|
|
{
|
|
foreach (var (name, content) in files)
|
|
{
|
|
var entry = archive.CreateEntry(name);
|
|
using var writer = new StreamWriter(entry.Open());
|
|
writer.Write(content);
|
|
}
|
|
}
|
|
return stream.ToArray();
|
|
}
|
|
|
|
static void WriteSearchFixtureFiles(string root)
|
|
{
|
|
File.WriteAllText(Path.Combine(root, "2026-02-01.md"), """
|
|
Date: 2026-02-01
|
|
## Summary
|
|
Alpha common
|
|
## Reflection
|
|
focus area
|
|
- [x] med taken
|
|
!TRIGGER #stress
|
|
fragment one
|
|
""");
|
|
|
|
File.WriteAllText(Path.Combine(root, "2026-02-05.md"), """
|
|
Date: 2026-02-05
|
|
## Summary
|
|
Beta common
|
|
## Reflection
|
|
other notes
|
|
- [ ] drink water
|
|
!NOTE #daily
|
|
fragment two
|
|
""");
|
|
|
|
File.WriteAllText(Path.Combine(root, "2026-03-01.md"), """
|
|
Date: 2026-03-01
|
|
## Summary
|
|
Gamma unique
|
|
## Reflection
|
|
nothing related
|
|
!NOTE #other
|
|
fragment three
|
|
""");
|
|
}
|
|
|
|
static (int ExitCode, string Stdout, string Stderr) CaptureConsole(Func<int> action)
|
|
{
|
|
var originalOut = Console.Out;
|
|
var originalError = Console.Error;
|
|
using var stdout = new StringWriter();
|
|
using var stderr = new StringWriter();
|
|
|
|
try
|
|
{
|
|
Console.SetOut(stdout);
|
|
Console.SetError(stderr);
|
|
var exitCode = action();
|
|
return (exitCode, stdout.ToString(), stderr.ToString());
|
|
}
|
|
finally
|
|
{
|
|
Console.SetOut(originalOut);
|
|
Console.SetError(originalError);
|
|
}
|
|
}
|
|
|
|
static async Task<List<TransportFixture>> LoadTransportFixturesAsync()
|
|
{
|
|
var path = Path.Combine(AppContext.BaseDirectory, "Fixtures", "transport_cases.json");
|
|
if (!File.Exists(path))
|
|
throw new FileNotFoundException($"Transport fixture file not found: {path}");
|
|
|
|
var json = await File.ReadAllTextAsync(path);
|
|
return JsonSerializer.Deserialize<List<TransportFixture>>(json, new JsonSerializerOptions
|
|
{
|
|
PropertyNameCaseInsensitive = true
|
|
}) ?? [];
|
|
}
|
|
|
|
static JsonValueKind ParseValueKind(string value) => value.Trim().ToLowerInvariant() switch
|
|
{
|
|
"array" => JsonValueKind.Array,
|
|
"object" => JsonValueKind.Object,
|
|
"null" => JsonValueKind.Null,
|
|
"string" => JsonValueKind.String,
|
|
"number" => JsonValueKind.Number,
|
|
"true" => JsonValueKind.True,
|
|
"false" => JsonValueKind.False,
|
|
_ => throw new InvalidOperationException($"Unsupported JsonValueKind '{value}' in transport fixture.")
|
|
};
|
|
|
|
static void Assert(bool condition, string message)
|
|
{
|
|
if (!condition)
|
|
throw new InvalidOperationException(message);
|
|
}
|
|
}
|
|
|