Finalize turn-role invariants and legacy migration cutover

This commit is contained in:
ejclaw
2026-04-10 11:44:34 +09:00
parent 7753ee46f0
commit c67bd1c622
45 changed files with 15014 additions and 1381 deletions

View File

@@ -5,9 +5,6 @@
import fs from 'fs';
import path from 'path';
import { Database } from 'bun:sqlite';
import { STORE_DIR } from '../src/config.js';
import { logger } from '../src/logger.js';
import {
canUseLinuxBubblewrapReadonlySandbox,
@@ -17,8 +14,18 @@ import {
isHeadless,
isWSL,
} from './platform.js';
import {
detectRoomRegistrationState,
getLegacyMigrationGuidance,
} from './room-registration-state.js';
import { emitStatus } from './status.js';
export function detectAssignedRooms(
options?: Parameters<typeof detectRoomRegistrationState>[0],
): boolean {
return detectRoomRegistrationState(options).assignedRooms > 0;
}
export async function run(_args: string[]): Promise<void> {
const projectRoot = process.cwd();
@@ -30,9 +37,7 @@ export async function run(_args: string[]): Promise<void> {
const hasBubblewrap = platform === 'linux' && commandExists('bwrap');
const hasSocat = platform === 'linux' && commandExists('socat');
const apparmorRestrictUnprivilegedUserns =
platform === 'linux'
? getAppArmorRestrictUnprivilegedUsernsValue()
: null;
platform === 'linux' ? getAppArmorRestrictUnprivilegedUsernsValue() : null;
const hasBubblewrapReadonlySandboxCapability =
platform === 'linux' && canUseLinuxBubblewrapReadonlySandbox();
@@ -42,26 +47,15 @@ export async function run(_args: string[]): Promise<void> {
const authDir = path.join(projectRoot, 'store', 'auth');
const hasAuth = fs.existsSync(authDir) && fs.readdirSync(authDir).length > 0;
let hasRegisteredGroups = false;
// Check JSON file first (pre-migration)
if (fs.existsSync(path.join(projectRoot, 'data', 'registered_groups.json'))) {
hasRegisteredGroups = true;
} else {
// Check SQLite directly using better-sqlite3 (no sqlite3 CLI needed)
const dbPath = path.join(STORE_DIR, 'messages.db');
if (fs.existsSync(dbPath)) {
try {
const db = new Database(dbPath, { readonly: true });
const row = db
.prepare('SELECT COUNT(*) as count FROM registered_groups')
.get() as { count: number };
if (row.count > 0) hasRegisteredGroups = true;
db.close();
} catch {
// Table might not exist yet
}
}
}
const roomState = detectRoomRegistrationState({
projectRoot,
dbPath: path.join(projectRoot, 'store', 'messages.db'),
});
const legacyMigrationGuidance = getLegacyMigrationGuidance(
roomState,
'setup',
);
const status = legacyMigrationGuidance ? 'failed' : 'success';
logger.info(
{
@@ -69,7 +63,13 @@ export async function run(_args: string[]): Promise<void> {
wsl,
hasEnv,
hasAuth,
hasRegisteredGroups,
assignedRooms: roomState.assignedRooms,
legacyRegisteredGroupRows: roomState.legacyRegisteredGroupRows,
hasLegacyRegisteredGroupsJson: roomState.hasLegacyRegisteredGroupsJson,
legacyRoomMigrationRequired: roomState.legacyRoomMigrationRequired,
pendingLegacyJsonStateFiles: roomState.pendingLegacyJsonStateFiles,
legacyJsonStateMigrationRequired:
roomState.legacyJsonStateMigrationRequired,
hasBubblewrap,
hasSocat,
apparmorRestrictUnprivilegedUserns,
@@ -84,14 +84,30 @@ export async function run(_args: string[]): Promise<void> {
IS_HEADLESS: headless,
HAS_ENV: hasEnv,
HAS_AUTH: hasAuth,
HAS_REGISTERED_GROUPS: hasRegisteredGroups,
HAS_ASSIGNED_ROOMS: roomState.assignedRooms > 0,
ASSIGNED_ROOMS: roomState.assignedRooms,
LEGACY_REGISTERED_GROUP_ROWS: roomState.legacyRegisteredGroupRows,
HAS_LEGACY_REGISTERED_GROUPS_JSON: roomState.hasLegacyRegisteredGroupsJson,
LEGACY_ROOM_MIGRATION_REQUIRED: roomState.legacyRoomMigrationRequired,
PENDING_LEGACY_JSON_STATE_FILES:
roomState.pendingLegacyJsonStateFiles.join(','),
LEGACY_JSON_STATE_MIGRATION_REQUIRED:
roomState.legacyJsonStateMigrationRequired,
HAS_BWRAP: hasBubblewrap,
HAS_SOCAT: hasSocat,
APPARMOR_RESTRICT_UNPRIVILEGED_USERNS:
apparmorRestrictUnprivilegedUserns ?? 'n/a',
HAS_BWRAP_READONLY_SANDBOX_CAPABILITY:
hasBubblewrapReadonlySandboxCapability,
STATUS: 'success',
...(legacyMigrationGuidance
? {
ERROR: legacyMigrationGuidance.error,
NEXT_STEP: legacyMigrationGuidance.nextStep,
}
: {}),
STATUS: status,
LOG: 'logs/setup.log',
});
if (status === 'failed') process.exit(1);
}