mirror of
https://github.com/hellodigua/ChatLab.git
synced 2026-10-25 17:54:34 +08:00
feat(owner): auto-apply owner profile after pull sync and CLI import
PullEngine gains an onSessionImported hook (hook errors never fail the pull), wired in both the CLI server and Electron main to silently fill session owner from the stored platform profile. The chatlab import CLI command does the same after a successful import. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
This commit is contained in:
1 parent
502762bcf5
commit
82ce9dcc2f
5 files changed
+64
-2
No files matched your search
+18
-1
@@ -242,7 +242,7 @@ program
|
|||||||
}
|
}
|
||||||
|
|
||||||
const { streamImport, detectFormat } = await import('./import')
|
const { streamImport, detectFormat } = await import('./import')
|
||||||
const { dbManager } = initRuntime()
|
const { dbManager, pathProvider } = initRuntime()
|
||||||
const nativeBinding = resolveNativeBinding()
|
const nativeBinding = resolveNativeBinding()
|
||||||
|
|
||||||
const format = detectFormat(file)
|
const format = detectFormat(file)
|
||||||
@@ -269,6 +269,23 @@ program
|
|||||||
console.log(` Session ID: ${result.sessionId}`)
|
console.log(` Session ID: ${result.sessionId}`)
|
||||||
console.log(` Messages written: ${result.diagnostics?.messagesWritten ?? 0}`)
|
console.log(` Messages written: ${result.diagnostics?.messagesWritten ?? 0}`)
|
||||||
console.log(` Messages skipped: ${result.diagnostics?.messagesSkipped ?? 0}`)
|
console.log(` Messages skipped: ${result.diagnostics?.messagesSkipped ?? 0}`)
|
||||||
|
|
||||||
|
if (result.sessionId) {
|
||||||
|
try {
|
||||||
|
const { PreferencesManager, createDatabaseManagerAdapter, ownerProfileService } =
|
||||||
|
await import('@openchatlab/node-runtime')
|
||||||
|
const applied = ownerProfileService.tryApplyOwnerProfile(
|
||||||
|
createDatabaseManagerAdapter(dbManager),
|
||||||
|
new PreferencesManager(pathProvider.getSystemDir()),
|
||||||
|
result.sessionId
|
||||||
|
)
|
||||||
|
if (applied.applied) {
|
||||||
|
console.log(` Owner auto-detected: ${applied.ownerId}`)
|
||||||
|
}
|
||||||
|
} catch (ownerErr) {
|
||||||
|
console.warn(` Owner profile apply skipped: ${ownerErr instanceof Error ? ownerErr.message : ownerErr}`)
|
||||||
|
}
|
||||||
|
}
|
||||||
} else {
|
} else {
|
||||||
console.error(`\n\nImport failed: ${result.error}`)
|
console.error(`\n\nImport failed: ${result.error}`)
|
||||||
process.exit(1)
|
process.exit(1)
|
||||||
|
|||||||
@@ -6,6 +6,7 @@
|
|||||||
|
|
||||||
import type { FastifyInstance } from 'fastify'
|
import type { FastifyInstance } from 'fastify'
|
||||||
import type { DatabaseManager } from '@openchatlab/node-runtime'
|
import type { DatabaseManager } from '@openchatlab/node-runtime'
|
||||||
|
import { PreferencesManager, createDatabaseManagerAdapter, ownerProfileService } from '@openchatlab/node-runtime'
|
||||||
import type { PathProvider } from '@openchatlab/core'
|
import type { PathProvider } from '@openchatlab/core'
|
||||||
import { DataSourceManager, PullEngine, initScheduler, stopAllTimers } from '@openchatlab/sync'
|
import { DataSourceManager, PullEngine, initScheduler, stopAllTimers } from '@openchatlab/sync'
|
||||||
import type { SyncLogger } from '@openchatlab/sync'
|
import type { SyncLogger } from '@openchatlab/sync'
|
||||||
@@ -42,12 +43,21 @@ export function initSync(
|
|||||||
const importer = new DirectImporter(dbManager, syncLogger)
|
const importer = new DirectImporter(dbManager, syncLogger)
|
||||||
const notifier = new NoopNotifier()
|
const notifier = new NoopNotifier()
|
||||||
|
|
||||||
|
const sessionAdapter = createDatabaseManagerAdapter(dbManager)
|
||||||
|
const preferences = new PreferencesManager(pathProvider.getSystemDir())
|
||||||
|
|
||||||
pullEngine = new PullEngine({
|
pullEngine = new PullEngine({
|
||||||
fetcher,
|
fetcher,
|
||||||
importer,
|
importer,
|
||||||
notifier,
|
notifier,
|
||||||
dsManager,
|
dsManager,
|
||||||
logger: syncLogger,
|
logger: syncLogger,
|
||||||
|
onSessionImported: (localSessionId) => {
|
||||||
|
const result = ownerProfileService.tryApplyOwnerProfile(sessionAdapter, preferences, localSessionId)
|
||||||
|
if (result.applied) {
|
||||||
|
syncLogger.info(`[Pull] Applied owner profile to session ${localSessionId} (owner: ${result.ownerId})`)
|
||||||
|
}
|
||||||
|
},
|
||||||
})
|
})
|
||||||
|
|
||||||
registerAutomationRoutes(server, { dsManager, pullEngine, dbManager, serverInfo })
|
registerAutomationRoutes(server, { dsManager, pullEngine, dbManager, serverInfo })
|
||||||
|
|||||||
@@ -256,6 +256,11 @@ export function getInternalEndpoint(): InternalEndpoint | null {
|
|||||||
return endpoint
|
return endpoint
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/** Main-process DatabaseManager backing the internal server (null before startup). */
|
||||||
|
export function getInternalDbManager(): DatabaseManager | null {
|
||||||
|
return dbManager
|
||||||
|
}
|
||||||
|
|
||||||
export async function stopInternalServer(): Promise<void> {
|
export async function stopInternalServer(): Promise<void> {
|
||||||
if (!server) return
|
if (!server) return
|
||||||
try {
|
try {
|
||||||
|
|||||||
@@ -8,10 +8,12 @@ import { ipcMain, net } from 'electron'
|
|||||||
import type { IpcContext } from './types'
|
import type { IpcContext } from './types'
|
||||||
import * as apiServer from '../api'
|
import * as apiServer from '../api'
|
||||||
import { setConfigManager } from '../api'
|
import { setConfigManager } from '../api'
|
||||||
import { getSettingsDir } from '../paths'
|
import { getSettingsDir, getSystemDataDir } from '../paths'
|
||||||
import { apiLogger } from '../api/logger'
|
import { apiLogger } from '../api/logger'
|
||||||
import { getImportingStatus } from '../api/routes/import'
|
import { getImportingStatus } from '../api/routes/import'
|
||||||
import { deleteSession as deleteSessionFile } from '../database/core'
|
import { deleteSession as deleteSessionFile } from '../database/core'
|
||||||
|
import { getInternalDbManager } from '../internal-api'
|
||||||
|
import { PreferencesManager, createDatabaseManagerAdapter, ownerProfileService } from '@openchatlab/node-runtime'
|
||||||
import { ElectronFetcher, WorkerImporter, BrowserWindowNotifier } from '../api/adapters'
|
import { ElectronFetcher, WorkerImporter, BrowserWindowNotifier } from '../api/adapters'
|
||||||
import {
|
import {
|
||||||
ConfigManager,
|
ConfigManager,
|
||||||
@@ -52,6 +54,19 @@ function ensureInstances(): void {
|
|||||||
dsManager,
|
dsManager,
|
||||||
logger: syncLogger,
|
logger: syncLogger,
|
||||||
isImporting: getImportingStatus,
|
isImporting: getImportingStatus,
|
||||||
|
onSessionImported: (localSessionId) => {
|
||||||
|
// Resolve lazily: the internal server (and its DatabaseManager) starts after IPC registration
|
||||||
|
const dbManager = getInternalDbManager()
|
||||||
|
if (!dbManager) return
|
||||||
|
const result = ownerProfileService.tryApplyOwnerProfile(
|
||||||
|
createDatabaseManagerAdapter(dbManager),
|
||||||
|
new PreferencesManager(getSystemDataDir()),
|
||||||
|
localSessionId
|
||||||
|
)
|
||||||
|
if (result.applied) {
|
||||||
|
syncLogger.info(`[Pull] Applied owner profile to session ${localSessionId} (owner: ${result.ownerId})`)
|
||||||
|
}
|
||||||
|
},
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -120,6 +120,12 @@ export interface PullEngineOptions {
|
|||||||
logger?: SyncLogger
|
logger?: SyncLogger
|
||||||
/** Return true when an import is already in progress (skip pull) */
|
/** Return true when an import is already in progress (skip pull) */
|
||||||
isImporting?: () => boolean
|
isImporting?: () => boolean
|
||||||
|
/**
|
||||||
|
* Called after a pull session completes successfully with the local session ID.
|
||||||
|
* Used for post-import side effects (e.g. applying the platform owner profile).
|
||||||
|
* Errors thrown by the hook never fail the pull.
|
||||||
|
*/
|
||||||
|
onSessionImported?: (localSessionId: string) => void
|
||||||
}
|
}
|
||||||
|
|
||||||
export class PullEngine {
|
export class PullEngine {
|
||||||
@@ -129,6 +135,7 @@ export class PullEngine {
|
|||||||
private dsManager: DataSourceManager
|
private dsManager: DataSourceManager
|
||||||
private logger: SyncLogger
|
private logger: SyncLogger
|
||||||
private isImporting: () => boolean
|
private isImporting: () => boolean
|
||||||
|
private onSessionImported?: (localSessionId: string) => void
|
||||||
private pullingSourceIds = new Set<string>()
|
private pullingSourceIds = new Set<string>()
|
||||||
private progressMap = new Map<string, PullProgress>()
|
private progressMap = new Map<string, PullProgress>()
|
||||||
|
|
||||||
@@ -139,6 +146,7 @@ export class PullEngine {
|
|||||||
this.dsManager = options.dsManager
|
this.dsManager = options.dsManager
|
||||||
this.logger = options.logger ?? NOOP_LOGGER
|
this.logger = options.logger ?? NOOP_LOGGER
|
||||||
this.isImporting = options.isImporting ?? (() => false)
|
this.isImporting = options.isImporting ?? (() => false)
|
||||||
|
this.onSessionImported = options.onSessionImported
|
||||||
}
|
}
|
||||||
|
|
||||||
getProgress(): PullProgress[] {
|
getProgress(): PullProgress[] {
|
||||||
@@ -372,6 +380,13 @@ export class PullEngine {
|
|||||||
if (totalNewMessages > 0) this.notifier.onSessionListChanged()
|
if (totalNewMessages > 0) this.notifier.onSessionListChanged()
|
||||||
this.notifier.onPullResult(sourceId, sess.id, 'success', `+${totalNewMessages} messages`)
|
this.notifier.onPullResult(sourceId, sess.id, 'success', `+${totalNewMessages} messages`)
|
||||||
this.markProgressDone(sess.id)
|
this.markProgressDone(sess.id)
|
||||||
|
if (this.onSessionImported && sess.targetSessionId) {
|
||||||
|
try {
|
||||||
|
this.onSessionImported(sess.targetSessionId)
|
||||||
|
} catch (hookErr) {
|
||||||
|
this.logger.warn(`[Pull] onSessionImported hook failed for "${sess.name}": ${hookErr}`)
|
||||||
|
}
|
||||||
|
}
|
||||||
return { success: true, newMessageCount: totalNewMessages }
|
return { success: true, newMessageCount: totalNewMessages }
|
||||||
} catch (error: any) {
|
} catch (error: any) {
|
||||||
const errMsg = error.message || 'Pull failed'
|
const errMsg = error.message || 'Pull failed'
|
||||||
|
|||||||
Reference in new issue
Block a user