Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
7 changes: 7 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -112,3 +112,10 @@ yarn.lock
packages/loader/src/plugins.ts

legacy

_docs
_memory
.claude

CLAUDE.md
.satori/
7 changes: 6 additions & 1 deletion .vscode/settings.json
Original file line number Diff line number Diff line change
Expand Up @@ -60,5 +60,10 @@
"scss",
"pcss",
"postcss"
]
],
"chat.tools.terminal.autoApprove": {
"yarn workspace": true,
"yarn install": true,
"printf": true
}
}
8 changes: 3 additions & 5 deletions app/cirno/readme.md
Original file line number Diff line number Diff line change
@@ -1,6 +1,4 @@
# satoriapp-cirno
# app/cirno

> [!IMPORTANT]
> to be completed...

Satori App for Desktop (based on [Cirno App](https://github.com/cirno-app/cirno))
Satori App Cirno 版本(基于 [Cirno](https://github.com/cordiverse/cirno) 跨平台框架)。
等待 cordis 团队完成 Cirno 开发后,将从 Electron 迁移至此。
15 changes: 15 additions & 0 deletions app/electron-esm/electron.vite.config.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,6 @@
import { resolve } from 'node:path'
import yaml from '@rollup/plugin-yaml'
import vue from '@vitejs/plugin-vue'
import { defineConfig, externalizeDepsPlugin } from 'electron-vite'

import jsonImportAttributesPlugin from './vite/vite-plugin-import-attr'
Expand Down Expand Up @@ -33,9 +35,22 @@ export default defineConfig({
},
},
renderer: {
plugins: [yaml() as any, vue({
template: {
compilerOptions: {
isCustomElement: tag => tag.startsWith('fluent-'),
},
},
})],
resolve: {
alias: {
'@renderer': resolve('src/renderer/src'),
'@satoriapp/webui': resolve('../../packages/webui/src/index.ts'),
'@plugin/link-ipc': resolve('../../plugins/link-ipc/src/client.ts'),
'@plugin/link-ws': resolve('../../plugins/link-web/src/client.ts'),
'@plugin/client-messages': resolve('../../plugins/client-messages/client/index.ts'),
'@plugin/client-config': resolve('../../plugins/client-config/client/index.ts'),
'@plugin/client-person': resolve('../../plugins/client-person/client/index.ts'),
},
},
},
Expand Down
37 changes: 28 additions & 9 deletions app/electron-esm/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -43,23 +43,40 @@
"build:linux": "npm run build && electron-builder --linux"
},
"dependencies": {
"@cordisjs/plugin-http": "^0.6.3",
"@cordisjs/plugin-server": "^0.2.5",
"@cordisjs/plugin-database": "^4.0.1",
"@cordisjs/plugin-database-sqlite": "^5.0.4",
"@cordisjs/plugin-http": "^1.5.0",
"@cordisjs/plugin-loader": "^1.0.0-rc.3",
"@cordisjs/plugin-logger": "^1.0.2",
"@cordisjs/plugin-server": "^1.5.0",
"@electron-toolkit/preload": "^3.0.1",
"@electron-toolkit/utils": "^4.0.0",
"@satoriapp/app": "workspace:*",
"@satoriapp/loader": "workspace:*",
"@satoriapp/adapter": "workspace:*",
"@satoriapp/electron-loader": "workspace:*",
"@satoriapp/plugin-app-server": "workspace:*",
"@satoriapp/plugin-client-config": "workspace:*",
"@satoriapp/plugin-client-messages": "workspace:*",
"@satoriapp/plugin-client-person": "workspace:*",
"@satoriapp/plugin-conversation-sync": "workspace:*",
"@satoriapp/plugin-link-ipc": "workspace:*",
"@satoriapp/plugin-message": "workspace:*",
"@satoriapp/plugin-msgdb": "workspace:*",
"@satoriapp/plugin-resource-store": "workspace:*",
"@satoriapp/plugin-state": "workspace:*",
"@satoriapp/state": "workspace:*",
"@satoriapp/webui": "workspace:*",
"@satorijs/core": "^4.5.0",
"cordis": "3.18.1",
"cordis": "^4.0.0-rc.4",
"electron-squirrel-startup": "^1.0.1",
"electron-updater": "^6.3.9"
"electron-updater": "^6.3.9",
"schemastery": "^3.18.0"
},
"devDependencies": {
"@electron-toolkit/eslint-config-prettier": "3.0.0",
"@electron-toolkit/eslint-config-ts": "^3.0.0",
"@electron-toolkit/tsconfig": "^1.0.1",
"@rollup/plugin-yaml": "^4.1.2",
"@types/node": "^22.14.1",
"@vitejs/plugin-vue": "^6.0.5",
"electron": "35.1.5",
"electron-builder": "^25.1.8",
"electron-vite": "^3.1.0",
Expand All @@ -68,7 +85,9 @@
"eslint-plugin-vue": "^10.0.0",
"magic-string": "^0.30.17",
"prettier": "^3.5.3",
"typescript": "^5.8.3",
"vite": "^6.2.6"
"sass-embedded": "^1.98.0",
"typescript": "^6.0.3",
"vite": "^6.2.6",
"vue-tsc": "^2.2.12"
}
}
25 changes: 25 additions & 0 deletions app/electron-esm/src/main/config.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
import Schema from 'schemastery'

export interface WindowServiceConfig {
theme: 'dark' | 'light' | 'system'
width: number
height: number
}

export const WindowConfigSchema: Schema<WindowServiceConfig> = Schema.object({
theme: Schema.union(['dark', 'light', 'system']).default('system').description('主题模式'),
width: Schema.number().step(1).default(1076).description('窗口宽度'),
height: Schema.number().step(1).default(653).description('窗口高度'),
})

export interface RootConfig {
window?: WindowServiceConfig
locale?: string
autoLaunch?: boolean
}

export const RootConfigSchema: Schema<RootConfig> = Schema.object({
window: WindowConfigSchema,
locale: Schema.string().default('zh-CN').description('应用语言'),
autoLaunch: Schema.boolean().default(false).description('开机自启动'),
})
89 changes: 46 additions & 43 deletions app/electron-esm/src/main/index.ts
Original file line number Diff line number Diff line change
@@ -1,74 +1,77 @@
import type * as electron from 'electron'
import { resolve } from 'node:path'
import process from 'node:process'
import { fileURLToPath } from 'node:url'
import { APP_VERSION } from '@satoriapp/app'
import Loader from '@satoriapp/loader'
import { fileURLToPath, pathToFileURL } from 'node:url'
import { ElectronLoader, PluginStore } from '@satoriapp/electron-loader'
import { Context } from 'cordis'
import * as electorn from 'electron'
import * as electronModule from 'electron'
import started from 'electron-squirrel-startup'

import icon from '../../resources/icon.png?asset'
import { plugins } from './internals'
import WindowService from './window'
import { buildDefaultEntries, plugins } from './internals'

declare module 'cordis' {
interface Context {
app: electorn.App
$version: string
$env: { [key: string]: string }
app: electron.App
baseDir: string
version: string
env: { [key: string]: string }
}
}

let isQuiting = false

if (started) {
isQuiting = true
electorn.app.quit()
electronModule.app.exit(0)
}

const baseDir = resolve(electronModule.app.getPath('home'), '.satori-desktop')
const dbPath = resolve(baseDir, 'data.db')

const app = new Context()
app.baseUrl = pathToFileURL(`${baseDir}/`).href

app.provide('satori', undefined, true)
app.provide('bots', [], true)
app.provide('app', electorn.app, true)
app.set('$env', {
app.provide('app', electronModule.app)
app.provide('env', {
MAIN_WINDOW_ICON: icon,
MAIN_DEV_SERVER_URL: process.env.ELECTRON_RENDERER_URL,
MAIN_PROD_FILE: fileURLToPath(new URL('../renderer/index.html', import.meta.url)),
PRELOAD_PATH: fileURLToPath(new URL('../preload/index.mjs', import.meta.url)),
})
app.set('$version', APP_VERSION)
app.provide('version', '0.1.0')
app.provide('baseDir', baseDir)

app.dataDir = resolve(electorn.app.getPath('home'), '.sapp')
app.plugin(Loader)
app.inject(['loader', 'app'], (ctx) => {
ctx.loader._mixins(plugins)
ctx.loader.init()
app.plugin(ElectronLoader, {
baseDir,
internals: plugins,
defaultEntries: buildDefaultEntries(plugins, dbPath),
})
app.plugin(PluginStore, { baseDir })

app.on('dispose', () => {
isQuiting = true
electorn.app.quit()
})
let isShuttingDown = false

electorn.app.on('window-all-closed', () => {
if (process.platform !== 'darwin') {
electorn.app.quit()
async function shutdown() {
if (isShuttingDown)
return
isShuttingDown = true
try {
await app.fiber.dispose()
}
})
catch {}
electronModule.app.exit(0)
}

electorn.app.on('before-quit', (e) => {
if (!isQuiting) {
e.preventDefault()
app.stop()
}
electronModule.app.on('window-all-closed', () => {
void shutdown()
})

electorn.app.on('ready', () => {
app.plugin(WindowService, app.loader.config.$window || {
theme: 'system',
width: 1076,
height: 653,
})
app.start()
electronModule.app.on('before-quit', (e) => {
if (isShuttingDown)
return
e.preventDefault()
void shutdown()
})

process.on('SIGINT', () => void shutdown())
process.on('SIGTERM', () => void shutdown())
process.on('SIGHUP', () => void shutdown())

electronModule.app.whenReady().then(() => app.fiber.await())
85 changes: 44 additions & 41 deletions app/electron-esm/src/main/internals.ts
Original file line number Diff line number Diff line change
@@ -1,46 +1,49 @@
import type { PluginManifest } from '@satoriapp/loader'
import type { EntryOptions } from '@cordisjs/plugin-loader'
import type { PluginManifest } from '@satoriapp/electron-loader'
import AppServer from '@satoriapp/plugin-app-server'
import ClientMessages from '@satoriapp/plugin-client-messages'
import ConversationSync from '@satoriapp/plugin-conversation-sync'
import Link from '@satoriapp/plugin-link-ipc'
import Message from '@satoriapp/plugin-message'
import * as MsgDb from '@satoriapp/plugin-msgdb'
import * as ResourceStore from '@satoriapp/plugin-resource-store'
import State from '@satoriapp/plugin-state'
import Database from '@cordisjs/plugin-database'
import DatabaseSqlite from '@cordisjs/plugin-database-sqlite'
import HTTP from '@cordisjs/plugin-http'
import HTTPPkg from '@cordisjs/plugin-http/package.json' with { type: 'json' }
import Logger from '@cordisjs/plugin-logger'
import Server from '@cordisjs/plugin-server'

import ServerPkg from '@cordisjs/plugin-server/package.json' with { type: 'json' }
import SatoriApp from '@satoriapp/app'
import SatoriAppPkg from '@satoriapp/app/package.json' with { type: 'json' }
import Satori from '@satorijs/core'

import SatoriPkg from '@satorijs/core/package.json' with { type: 'json' }
import WindowService from './window'

export const plugins: PluginManifest[] = [
{
name: 'satori',
packageName: '@satorijs/core',
meta: SatoriPkg.cordis || {},
version: SatoriPkg.version,
internal: true,
plugin: Satori,
},
{
name: 'http',
packageName: '@cordisjs/plugin-http',
meta: {},
version: HTTPPkg.version,
internal: true,
plugin: HTTP,
},
{
name: 'server',
packageName: '@cordisjs/plugin-server',
meta: {},
version: ServerPkg.version,
internal: true,
plugin: Server,
},
{
name: 'sapp',
packageName: '@satoriapp/app',
meta: {},
version: SatoriAppPkg.version,
internal: true,
plugin: SatoriApp,
},
{ name: 'logger', plugin: Logger },
{ name: 'database', plugin: Database },
{ name: 'database-sqlite', plugin: DatabaseSqlite },
{ name: 'http', plugin: HTTP },
{ name: 'server', plugin: Server },
{ name: 'link', plugin: Link },
{ name: 'app-server', plugin: AppServer },
{ name: 'state', plugin: State },
{ name: 'msgdb', plugin: MsgDb },
{ name: 'resource-store', plugin: ResourceStore },
{ name: 'message', plugin: Message },
{ name: 'conversation-sync', plugin: ConversationSync },
{ name: 'client-messages', plugin: ClientMessages },
{ name: 'window', plugin: WindowService },
]

export function buildDefaultEntries(manifests: PluginManifest[], dbPath: string): EntryOptions[] {
return manifests.map((m) => {
const entry: EntryOptions = {
id: `builtin-${m.name}`,
name: `cordis:${m.name}`,
}
if (m.name === 'database-sqlite')
entry.config = { path: dbPath }
if (m.name === 'server')
entry.config = { host: '127.0.0.1', port: 5140 }
if (m.name === 'window')
entry.config = { theme: 'system', width: 1076, height: 653 }
return entry
})
}
Loading
Loading