fix(hachidori): preserve setup completion while host connects

- Reopen setup only when a reachable host has no dictionaries
This commit is contained in:
2026-09-24 14:02:27 -07:00
parent 52fc1b63e9
commit 874d2c9f1a
2 changed files with 13 additions and 5 deletions
@@ -892,12 +892,13 @@ test('Hachidori setup gates on the linked host instead of local dictionaries', a
assert.equal(snapshot.dictionaryCount, 2); assert.equal(snapshot.dictionaryCount, 2);
assert.equal(snapshot.canFinish, true); assert.equal(snapshot.canFinish, true);
assert.equal((await service.markSetupCompleted()).state.status, 'completed'); assert.equal((await service.markSetupCompleted()).state.status, 'completed');
host = { kind: 'disconnected', address: 'ws://127.0.0.1:8771/link', message: 'Host offline' }; // The link is still connecting at startup; that must not undo a finished setup.
host = { kind: 'disconnected', address: 'ws://127.0.0.1:8771/link', message: 'Connecting' };
snapshot = await service.ensureSetupStateInitialized(); snapshot = await service.ensureSetupStateInitialized();
assert.equal(snapshot.canFinish, false); assert.equal(snapshot.canFinish, false);
assert.equal(snapshot.dictionaryCount, 0); assert.equal(snapshot.dictionaryCount, 0);
assert.equal(snapshot.state.status, 'incomplete'); assert.equal(snapshot.state.status, 'completed');
assert.notEqual((await service.markSetupCompleted()).state.status, 'completed'); assert.equal(service.isSetupCompleted(), true);
host = { host = {
kind: 'connected', kind: 'connected',
address: 'ws://127.0.0.1:8771/link', address: 'ws://127.0.0.1:8771/link',
@@ -905,6 +906,9 @@ test('Hachidori setup gates on the linked host instead of local dictionaries', a
dictionaryCount: 0, dictionaryCount: 0,
}; };
assert.equal((await service.getSetupStatus()).canFinish, false); assert.equal((await service.getSetupStatus()).canFinish, false);
// A reachable host with no dictionaries does reopen setup.
assert.equal((await service.ensureSetupStateInitialized()).state.status, 'incomplete');
assert.notEqual((await service.markSetupCompleted()).state.status, 'completed');
host = { kind: 'local' }; host = { kind: 'local' };
assert.equal((await service.getSetupStatus()).dictionaryCount, 7); assert.equal((await service.getSetupStatus()).dictionaryCount, 7);
assert.equal((await service.getSetupStatus()).canFinish, true); assert.equal((await service.getSetupStatus()).canFinish, true);
+6 -2
View File
@@ -448,7 +448,7 @@ export function createFirstRunSetupService(deps: {
getSetupStateDictionaryBackend(stored) === getDictionaryBackend() getSetupStateDictionaryBackend(stored) === getDictionaryBackend()
? stored ? stored
: writeState(projectState(stored)); : writeState(projectState(stored));
const { configReady, dictionaryCount, externalYomitanConfigured } = const { configReady, dictionaryCount, externalYomitanConfigured, hachidoriHost } =
await resolveYomitanSetupStatus({ await resolveYomitanSetupStatus({
configFilePaths, configFilePaths,
getYomitanDictionaryCount: deps.getYomitanDictionaryCount, getYomitanDictionaryCount: deps.getYomitanDictionaryCount,
@@ -461,7 +461,11 @@ export function createFirstRunSetupService(deps: {
dictionaryCount, dictionaryCount,
externalYomitanConfigured, externalYomitanConfigured,
}); });
if (isSetupCompleted(state) && canFinish) { // A linked host is usually still connecting at startup, so an unreachable host
// says nothing about its dictionaries; only a reachable empty host reopens setup.
const hostUnreachable =
hachidoriHost?.kind === 'disconnected' || hachidoriHost?.kind === 'unavailable';
if (isSetupCompleted(state) && (canFinish || (configReady && hostUnreachable))) {
completed = true; completed = true;
return refreshWithState(state); return refreshWithState(state);
} }