@koishi-ce/client 1.0.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/app/assets/logo.png +0 -0
- package/app/home/home.vue +51 -0
- package/app/home/index.ts +18 -0
- package/app/home/welcome.en-US.yml +9 -0
- package/app/home/welcome.vue +111 -0
- package/app/home/welcome.zh-CN.yml +9 -0
- package/app/index.html +13 -0
- package/app/index.scss +64 -0
- package/app/index.ts +32 -0
- package/app/layout/header.vue +187 -0
- package/app/layout/index.ts +15 -0
- package/app/layout/layout.vue +194 -0
- package/app/layout/menu-item.vue +60 -0
- package/app/settings/index.ts +39 -0
- package/app/settings/settings.vue +82 -0
- package/app/settings/theme.vue +123 -0
- package/app/shims.d.ts +1 -0
- package/app/status/index.ts +21 -0
- package/app/status/loading.vue +23 -0
- package/app/status/status.vue +56 -0
- package/app/styles/element.scss +217 -0
- package/app/styles/hc.scss +35 -0
- package/app/styles/index.scss +140 -0
- package/app/styles/index.ts +30 -0
- package/app/styles/layout.scss +92 -0
- package/app/theme/activity/button.vue +97 -0
- package/app/theme/activity/index.vue +119 -0
- package/app/theme/activity/item.vue +185 -0
- package/app/theme/activity/separator.vue +163 -0
- package/app/theme/activity/utils.ts +27 -0
- package/app/theme/blank.vue +24 -0
- package/app/theme/index.ts +37 -0
- package/app/theme/index.vue +34 -0
- package/app/theme/menu/index.vue +26 -0
- package/app/theme/menu/menu-item.vue +58 -0
- package/app/theme/menu/menu.vue +45 -0
- package/app/theme/status.vue +45 -0
- package/app/tsconfig.json +15 -0
- package/client/components/chat/image.vue +20 -0
- package/client/components/chat/overlay.vue +231 -0
- package/client/components/chat/utils.ts +6 -0
- package/client/components/common/index.ts +11 -0
- package/client/components/common/k-button.vue +127 -0
- package/client/components/common/k-hint.vue +62 -0
- package/client/components/common/k-tab.vue +50 -0
- package/client/components/dynamic.vue +61 -0
- package/client/components/icons/activity/default.vue +6 -0
- package/client/components/icons/activity/ellipsis.vue +6 -0
- package/client/components/icons/activity/home.vue +13 -0
- package/client/components/icons/activity/moon.vue +6 -0
- package/client/components/icons/activity/settings.vue +6 -0
- package/client/components/icons/activity/sun.vue +6 -0
- package/client/components/icons/index.ts +133 -0
- package/client/components/icons/style.scss +3 -0
- package/client/components/icons/svg/arrow-left.vue +6 -0
- package/client/components/icons/svg/arrow-right.vue +6 -0
- package/client/components/icons/svg/box-open.vue +6 -0
- package/client/components/icons/svg/check-full.vue +6 -0
- package/client/components/icons/svg/chevron-down.vue +6 -0
- package/client/components/icons/svg/chevron-left.vue +6 -0
- package/client/components/icons/svg/chevron-right.vue +6 -0
- package/client/components/icons/svg/chevron-up.vue +6 -0
- package/client/components/icons/svg/clipboard-list.vue +6 -0
- package/client/components/icons/svg/edit.vue +6 -0
- package/client/components/icons/svg/exclamation-full.vue +6 -0
- package/client/components/icons/svg/expand.vue +6 -0
- package/client/components/icons/svg/file-archive.vue +6 -0
- package/client/components/icons/svg/filter.vue +6 -0
- package/client/components/icons/svg/github.vue +6 -0
- package/client/components/icons/svg/gitlab.vue +6 -0
- package/client/components/icons/svg/info-full.vue +6 -0
- package/client/components/icons/svg/koishi.vue +6 -0
- package/client/components/icons/svg/link.vue +6 -0
- package/client/components/icons/svg/paper-plane.vue +6 -0
- package/client/components/icons/svg/question-empty.vue +6 -0
- package/client/components/icons/svg/redo.vue +6 -0
- package/client/components/icons/svg/search-minus.vue +6 -0
- package/client/components/icons/svg/search-plus.vue +6 -0
- package/client/components/icons/svg/search.vue +6 -0
- package/client/components/icons/svg/star-empty.vue +6 -0
- package/client/components/icons/svg/star-full.vue +6 -0
- package/client/components/icons/svg/start.vue +6 -0
- package/client/components/icons/svg/tag.vue +6 -0
- package/client/components/icons/svg/times-full.vue +6 -0
- package/client/components/icons/svg/tools.vue +6 -0
- package/client/components/icons/svg/undo.vue +6 -0
- package/client/components/icons/svg/user.vue +6 -0
- package/client/components/index.ts +75 -0
- package/client/components/layout/card.vue +69 -0
- package/client/components/layout/content.vue +37 -0
- package/client/components/layout/empty.vue +41 -0
- package/client/components/layout/index.ts +15 -0
- package/client/components/layout/tab-group.vue +45 -0
- package/client/components/layout/tab-item.vue +35 -0
- package/client/components/link.ts +39 -0
- package/client/components/perms.vue +73 -0
- package/client/components/slot.ts +95 -0
- package/client/context.ts +143 -0
- package/client/data.ts +178 -0
- package/client/index.ts +76 -0
- package/client/plugins/action.ts +251 -0
- package/client/plugins/i18n.ts +43 -0
- package/client/plugins/loader.ts +154 -0
- package/client/plugins/router.ts +278 -0
- package/client/plugins/setting.ts +217 -0
- package/client/plugins/theme.ts +134 -0
- package/client/shims.d.ts +55 -0
- package/client/tsconfig.json +15 -0
- package/client/utils.ts +36 -0
- package/global.d.ts +24 -0
- package/lib/bin.d.ts +1 -0
- package/lib/bin.mjs +112 -0
- package/lib/client-CaTn_gVG.mjs +125 -0
- package/lib/index.d.ts +20 -0
- package/lib/index.mjs +2 -0
- package/lib/src-Bxzzi1Rx.mjs +160 -0
- package/lib/yaml-UzQbvquH.mjs +23 -0
- package/package.json +66 -0
- package/src/bin.ts +61 -0
- package/src/index.ts +280 -0
- package/src/yaml.ts +22 -0
package/client/utils.ts
ADDED
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
import * as cordis from "cordis";
|
|
2
|
+
import { markRaw } from "vue";
|
|
3
|
+
import type { Context } from "./context";
|
|
4
|
+
|
|
5
|
+
/**
|
|
6
|
+
* 前端服务基类:继承 cordis.Service 并固定为本库的 Context 类型。
|
|
7
|
+
* 各核心服务(action / i18n / loader / router / setting / theme)均由此派生。
|
|
8
|
+
*/
|
|
9
|
+
export abstract class Service<
|
|
10
|
+
T = unknown,
|
|
11
|
+
C extends Context = Context,
|
|
12
|
+
> extends cordis.Service<T, C> {}
|
|
13
|
+
|
|
14
|
+
/** 可排序项:实现本接口的条目可被 insert() 按 order 插入有序列表 */
|
|
15
|
+
export interface Ordered {
|
|
16
|
+
order?: number;
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
/**
|
|
20
|
+
* 按 order 升序将条目插入有序列表(相同 order 的后者排在后面)。
|
|
21
|
+
* 同时 markRaw 标记条目,避免其被 Vue 深度代理。
|
|
22
|
+
*/
|
|
23
|
+
export function insert<T extends Ordered>(list: T[], item: T) {
|
|
24
|
+
markRaw(item);
|
|
25
|
+
// order 为可选属性:任一侧缺失(undefined)时数值比较结果恒为 false,
|
|
26
|
+
// 与原实现(直接比较)在所有输入下的求值结果一致,这里显式判空以通过严格空检查
|
|
27
|
+
const index = list.findIndex(
|
|
28
|
+
(a) =>
|
|
29
|
+
a.order !== undefined && item.order !== undefined && a.order < item.order,
|
|
30
|
+
);
|
|
31
|
+
if (index >= 0) {
|
|
32
|
+
list.splice(index, 0, item);
|
|
33
|
+
} else {
|
|
34
|
+
list.push(item);
|
|
35
|
+
}
|
|
36
|
+
}
|
package/global.d.ts
ADDED
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
/// <reference types="vue-i18n" />
|
|
2
|
+
/// <reference types="vite/client" />
|
|
3
|
+
/// <reference types="element-plus/global" />
|
|
4
|
+
|
|
5
|
+
// 以下为消费本包(@koishi-ce/client/global)的插件工程提供的环境类型垫片:
|
|
6
|
+
// .vue 单文件组件与 yaml / yml 文案文件在此仅声明为无结构导出,
|
|
7
|
+
// 具体类型由各工程的构建工具链(vite 插件)在编译期处理
|
|
8
|
+
|
|
9
|
+
declare module "*.vue" {
|
|
10
|
+
import { Component } from "vue";
|
|
11
|
+
|
|
12
|
+
const component: Component;
|
|
13
|
+
export default component;
|
|
14
|
+
}
|
|
15
|
+
|
|
16
|
+
declare module "*.yaml" {
|
|
17
|
+
const content: Record<never, never>;
|
|
18
|
+
export default content;
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
declare module "*.yml" {
|
|
22
|
+
const content: Record<never, never>;
|
|
23
|
+
export default content;
|
|
24
|
+
}
|
package/lib/bin.d.ts
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {}
|
package/lib/bin.mjs
ADDED
|
@@ -0,0 +1,112 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
import { t as build } from "./src-Bxzzi1Rx.mjs";
|
|
3
|
+
import { existsSync } from "node:fs";
|
|
4
|
+
import { resolve } from "node:path";
|
|
5
|
+
//#endregion
|
|
6
|
+
//#region src/bin.ts
|
|
7
|
+
/**
|
|
8
|
+
* `koishi-console` CLI 入口(构建产物 lib/bin.mjs 由 package.json 的
|
|
9
|
+
* bin 字段指向,仓库内亦可用 Bun 直接运行本源文件)。
|
|
10
|
+
*
|
|
11
|
+
* 极简手写 CLI(不引 CLI 框架):仅 `build [root]` 一个子命令 +
|
|
12
|
+
* help/version。带 root(或 cwd 本身是含 client/ 的插件目录)时构建
|
|
13
|
+
* 该 webui 插件的前端;否则执行宿主控制台前端总装(scripts/client.ts,
|
|
14
|
+
* 产物写入 plugins/webui/console/dist)。
|
|
15
|
+
*/
|
|
16
|
+
const { version } = {
|
|
17
|
+
name: "@koishi-ce/client",
|
|
18
|
+
description: "Koishi Console Client",
|
|
19
|
+
version: "1.0.0",
|
|
20
|
+
type: "module",
|
|
21
|
+
main: "client/index.ts",
|
|
22
|
+
exports: {
|
|
23
|
+
".": {
|
|
24
|
+
"source": "./src/index.ts",
|
|
25
|
+
"default": "./client/index.ts"
|
|
26
|
+
},
|
|
27
|
+
"./global": "./global.d.ts",
|
|
28
|
+
"./bin": "./lib/bin.mjs",
|
|
29
|
+
"./lib": "./lib/index.mjs",
|
|
30
|
+
"./package.json": "./package.json"
|
|
31
|
+
},
|
|
32
|
+
files: [
|
|
33
|
+
"app",
|
|
34
|
+
"client",
|
|
35
|
+
"lib",
|
|
36
|
+
"src",
|
|
37
|
+
"global.d.ts"
|
|
38
|
+
],
|
|
39
|
+
bin: { "koishi-console": "./lib/bin.mjs" },
|
|
40
|
+
contributors: ["Shigma <shigma10826@gmail.com>", "Oppenheymu <oppenheymu@gmail.com>"],
|
|
41
|
+
license: "AGPL-3.0",
|
|
42
|
+
repository: {
|
|
43
|
+
"type": "git",
|
|
44
|
+
"url": "git+https://github.com/Koishi-CE/koishi.git",
|
|
45
|
+
"directory": "packages/web/client"
|
|
46
|
+
},
|
|
47
|
+
bugs: { "url": "https://github.com/Koishi-CE/koishi/issues" },
|
|
48
|
+
homepage: "https://koishi.chat",
|
|
49
|
+
keywords: [
|
|
50
|
+
"bot",
|
|
51
|
+
"chatbot",
|
|
52
|
+
"koishi",
|
|
53
|
+
"plugin",
|
|
54
|
+
"webui",
|
|
55
|
+
"console",
|
|
56
|
+
"build"
|
|
57
|
+
],
|
|
58
|
+
dependencies: {
|
|
59
|
+
"@koishi-ce/components": "workspace:*",
|
|
60
|
+
"@satorijs/protocol": "^1.7.0",
|
|
61
|
+
"@vitejs/plugin-vue": "^6.0.8",
|
|
62
|
+
"@vueuse/core": "^14.4.0",
|
|
63
|
+
"cordis": "^3.18.1",
|
|
64
|
+
"cosmokit": "^1.8.1",
|
|
65
|
+
"element-plus": "^2.14.5",
|
|
66
|
+
"marked-vue": "^1.3.0",
|
|
67
|
+
"sass-embedded": "^1.102.0",
|
|
68
|
+
"unocss": "^66.8.1",
|
|
69
|
+
"vite": "^8.2.2",
|
|
70
|
+
"vue": "^3.5.42",
|
|
71
|
+
"vue-i18n": "^11.4.10",
|
|
72
|
+
"vue-router": "^5.2.0"
|
|
73
|
+
}
|
|
74
|
+
};
|
|
75
|
+
const help = `koishi-console/${version}
|
|
76
|
+
|
|
77
|
+
Usage:
|
|
78
|
+
$ koishi-console <command> [options]
|
|
79
|
+
|
|
80
|
+
Commands:
|
|
81
|
+
build [root] build the frontend of given webui plugin, or the host
|
|
82
|
+
console when omitted (or when cwd has no client/ dir)
|
|
83
|
+
|
|
84
|
+
Options:
|
|
85
|
+
-h, --help Display this message
|
|
86
|
+
-v, --version Display version number`;
|
|
87
|
+
async function main() {
|
|
88
|
+
const [command, ...args] = process.argv.slice(2);
|
|
89
|
+
if (command === void 0 || command === "-h" || command === "--help") {
|
|
90
|
+
console.log(help);
|
|
91
|
+
return;
|
|
92
|
+
}
|
|
93
|
+
if (command === "-v" || command === "--version") {
|
|
94
|
+
console.log(`koishi-console/${version}`);
|
|
95
|
+
return;
|
|
96
|
+
}
|
|
97
|
+
if (command === "build") {
|
|
98
|
+
const target = args.find((arg) => !arg.startsWith("-")) ?? (existsSync("client") ? "." : void 0);
|
|
99
|
+
if (target !== void 0) {
|
|
100
|
+
await build(resolve(process.cwd(), target));
|
|
101
|
+
return;
|
|
102
|
+
}
|
|
103
|
+
await (await import("./client-CaTn_gVG.mjs")).default();
|
|
104
|
+
return;
|
|
105
|
+
}
|
|
106
|
+
console.error(`Unknown command ${JSON.stringify(command)}.`);
|
|
107
|
+
console.log(help);
|
|
108
|
+
process.exitCode = 1;
|
|
109
|
+
}
|
|
110
|
+
await main();
|
|
111
|
+
//#endregion
|
|
112
|
+
export {};
|
|
@@ -0,0 +1,125 @@
|
|
|
1
|
+
import { t as yaml } from "./yaml-UzQbvquH.mjs";
|
|
2
|
+
import { createRequire } from "node:module";
|
|
3
|
+
import { appendFile } from "node:fs/promises";
|
|
4
|
+
import { resolve } from "node:path";
|
|
5
|
+
import vue from "@vitejs/plugin-vue";
|
|
6
|
+
import * as vite from "vite";
|
|
7
|
+
import mini from "unocss/preset-mini";
|
|
8
|
+
import unocss from "unocss/vite";
|
|
9
|
+
//#region \0rolldown/runtime.js
|
|
10
|
+
var __require = /* #__PURE__ */ (() => createRequire(import.meta.url))();
|
|
11
|
+
//#endregion
|
|
12
|
+
//#region scripts/client.ts
|
|
13
|
+
/**
|
|
14
|
+
* 宿主控制台前端的总装构建脚本(编程式 vite.build,本仓库没有 vite 配置文件)。
|
|
15
|
+
*
|
|
16
|
+
* 产物目录硬编码为 `plugins/webui/console/dist/`,内容分四部分:
|
|
17
|
+
* - 主应用(本包 `app/` 目录)→ `index.js`
|
|
18
|
+
* - client 组件库(本包 `client/` 目录)→ `client.js`(element-plus 单独成 chunk)
|
|
19
|
+
* - vue / vue-router / @vueuse/core 三个运行时共享包 → `vue.js` 等,
|
|
20
|
+
* 供主应用、client 与所有 webui 插件以 external 依赖的方式共享
|
|
21
|
+
*/
|
|
22
|
+
/**
|
|
23
|
+
* 定位某个依赖包在 node_modules 中的安装目录。
|
|
24
|
+
*
|
|
25
|
+
* @param id 依赖包名(须能被 require.resolve 解析到)
|
|
26
|
+
* @returns 形如 `<前缀>/node_modules/<id>` 的目录路径(统一为正斜杠)
|
|
27
|
+
*/
|
|
28
|
+
function findModulePath(id) {
|
|
29
|
+
const path = __require.resolve(id).replace(/\\/g, "/");
|
|
30
|
+
const keyword = `/node_modules/${id}/`;
|
|
31
|
+
return path.slice(0, path.indexOf(keyword)) + keyword.slice(0, -1);
|
|
32
|
+
}
|
|
33
|
+
const cwd = resolve(import.meta.dir, "../../../..");
|
|
34
|
+
const dist = `${cwd}/plugins/webui/console/dist`;
|
|
35
|
+
/**
|
|
36
|
+
* 通用构建函数:以 `root` 为构建根目录打一个 ES 模块包到 console dist。
|
|
37
|
+
*
|
|
38
|
+
* @param root 构建根目录(决定默认入口与 html 所在位置)
|
|
39
|
+
* @param config 额外的 vite 配置,逐层合并覆盖下方默认值
|
|
40
|
+
* @param isClient 标记本次构建的是否为 client 组件库本体。仅该构建需要
|
|
41
|
+
* 真实打包 vue-i18n(见下方别名说明),其余构建一律复用宿主的 client.js
|
|
42
|
+
* @returns rollup 构建结果(供调用方进一步处理产物)
|
|
43
|
+
*/
|
|
44
|
+
async function build(root, config = {}, isClient = false) {
|
|
45
|
+
const { rollupOptions = {} } = config.build || {};
|
|
46
|
+
return await vite.build({
|
|
47
|
+
root,
|
|
48
|
+
build: {
|
|
49
|
+
outDir: `${cwd}/plugins/webui/console/dist`,
|
|
50
|
+
emptyOutDir: true,
|
|
51
|
+
cssCodeSplit: false,
|
|
52
|
+
chunkSizeWarningLimit: 1024,
|
|
53
|
+
...config.build,
|
|
54
|
+
rollupOptions: {
|
|
55
|
+
...rollupOptions,
|
|
56
|
+
makeAbsoluteExternalsRelative: true,
|
|
57
|
+
external: [
|
|
58
|
+
`${root}/vue.js`,
|
|
59
|
+
`${root}/vue-router.js`,
|
|
60
|
+
`${root}/client.js`,
|
|
61
|
+
`${root}/vueuse.js`
|
|
62
|
+
],
|
|
63
|
+
output: {
|
|
64
|
+
format: "module",
|
|
65
|
+
entryFileNames: "[name].js",
|
|
66
|
+
chunkFileNames: "[name].js",
|
|
67
|
+
assetFileNames: "[name].[ext]",
|
|
68
|
+
...rollupOptions.output
|
|
69
|
+
}
|
|
70
|
+
}
|
|
71
|
+
},
|
|
72
|
+
plugins: [
|
|
73
|
+
vue(),
|
|
74
|
+
yaml(),
|
|
75
|
+
...config.plugins || []
|
|
76
|
+
],
|
|
77
|
+
resolve: { alias: {
|
|
78
|
+
vue: `${root}/vue.js`,
|
|
79
|
+
"vue-router": `${root}/vue-router.js`,
|
|
80
|
+
"@vueuse/core": `${root}/vueuse.js`,
|
|
81
|
+
"@koishi-ce/client": `${root}/client.js`,
|
|
82
|
+
"schemastery-vue/client": `${cwd}/packages/web/components/client/schemastery-vue-runtime.ts`,
|
|
83
|
+
...isClient ? { "vue-i18n": findModulePath("vue-i18n") + "/dist/vue-i18n.esm-browser.prod.js" } : { "vue-i18n": `${root}/client.js` }
|
|
84
|
+
} }
|
|
85
|
+
});
|
|
86
|
+
}
|
|
87
|
+
async function client_default() {
|
|
88
|
+
const { output } = await build(`${cwd}/packages/web/client/app`, { plugins: [unocss({ presets: [mini({ preflight: false })] })] });
|
|
89
|
+
await Promise.all([
|
|
90
|
+
Bun.write(`${dist}/vue.js`, Bun.file(`${findModulePath("vue")}/dist/vue.runtime.esm-browser.prod.js`)),
|
|
91
|
+
build(`${findModulePath("vue-router")}/dist`, { build: {
|
|
92
|
+
outDir: dist,
|
|
93
|
+
emptyOutDir: false,
|
|
94
|
+
rollupOptions: {
|
|
95
|
+
input: { "vue-router": `${findModulePath("vue-router")}/dist/vue-router.esm-browser.js` },
|
|
96
|
+
preserveEntrySignatures: "strict"
|
|
97
|
+
}
|
|
98
|
+
} }),
|
|
99
|
+
build(findModulePath("@vueuse/core"), { build: {
|
|
100
|
+
outDir: dist,
|
|
101
|
+
emptyOutDir: false,
|
|
102
|
+
rollupOptions: {
|
|
103
|
+
input: { vueuse: `${findModulePath("@vueuse/core")}/dist/index.js` },
|
|
104
|
+
preserveEntrySignatures: "strict"
|
|
105
|
+
}
|
|
106
|
+
} })
|
|
107
|
+
]);
|
|
108
|
+
await build(`${cwd}/packages/web/client/client`, { build: {
|
|
109
|
+
outDir: dist,
|
|
110
|
+
emptyOutDir: false,
|
|
111
|
+
rollupOptions: {
|
|
112
|
+
input: { client: `${cwd}/packages/web/client/client/index.ts` },
|
|
113
|
+
output: { manualChunks(id) {
|
|
114
|
+
return id.includes("element-plus") ? "element" : void 0;
|
|
115
|
+
} },
|
|
116
|
+
preserveEntrySignatures: "strict"
|
|
117
|
+
}
|
|
118
|
+
} }, true);
|
|
119
|
+
for (const file of output) if (file.type === "asset" && file.name === "style.css") {
|
|
120
|
+
if (file.source === void 0) continue;
|
|
121
|
+
await appendFile(`${dist}/style.css`, file.source);
|
|
122
|
+
}
|
|
123
|
+
}
|
|
124
|
+
//#endregion
|
|
125
|
+
export { client_default as default };
|
package/lib/index.d.ts
ADDED
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
import * as vite from "vite";
|
|
2
|
+
//#region src/index.d.ts
|
|
3
|
+
/**
|
|
4
|
+
* 构建单个 webui 插件的前端产物。
|
|
5
|
+
*
|
|
6
|
+
* @param root 插件目录(无 `client/` 子目录时视为该插件没有前端,直接跳过)
|
|
7
|
+
* @param config 额外的 vite 配置,逐层合并覆盖下方默认值
|
|
8
|
+
*/
|
|
9
|
+
declare function build(root: string, config?: vite.UserConfig): Promise<void>;
|
|
10
|
+
/**
|
|
11
|
+
* 创建开发模式下的 vite dev server(middlewareMode,不监听独立端口,
|
|
12
|
+
* 由宿主 HTTP 服务挂载到 `/vite/` 前缀下)。
|
|
13
|
+
*
|
|
14
|
+
* @param baseDir 用于圈定文件访问范围的工作区根目录
|
|
15
|
+
* @param config 额外的 vite 配置
|
|
16
|
+
* @returns vite 的 ViteDevServer 实例
|
|
17
|
+
*/
|
|
18
|
+
declare function createServer(baseDir: string, config?: vite.InlineConfig): Promise<vite.ViteDevServer>;
|
|
19
|
+
//#endregion
|
|
20
|
+
export { build, createServer };
|
package/lib/index.mjs
ADDED
|
@@ -0,0 +1,160 @@
|
|
|
1
|
+
import { t as yaml } from "./yaml-UzQbvquH.mjs";
|
|
2
|
+
import { existsSync } from "node:fs";
|
|
3
|
+
import { mkdir, rm } from "node:fs/promises";
|
|
4
|
+
import { resolve } from "node:path";
|
|
5
|
+
import vue from "@vitejs/plugin-vue";
|
|
6
|
+
import * as vite from "vite";
|
|
7
|
+
//#region src/index.ts
|
|
8
|
+
/**
|
|
9
|
+
* @koishi-ce/client 构建入口。
|
|
10
|
+
*
|
|
11
|
+
* 提供两个编程式 API(本仓库的前端构建没有 vite 配置文件,全部在此完成):
|
|
12
|
+
* - `build(root)`:构建单个 webui 插件的前端(`<插件目录>/client/` → `dist/`),
|
|
13
|
+
* 由 `koishi-console` CLI(src/bin.ts)暴露给各插件使用;
|
|
14
|
+
* - `createServer(baseDir)`:创建开发模式的 vite 中间件服务器。
|
|
15
|
+
*/
|
|
16
|
+
async function collectWorkspaceAliases() {
|
|
17
|
+
const repoRoot = resolve(import.meta.dir, "../../../..").replace(/\\/g, "/");
|
|
18
|
+
const manifest = await Bun.file(`${repoRoot}/package.json`).json();
|
|
19
|
+
const aliases = {};
|
|
20
|
+
for (const pattern of manifest.workspaces ?? []) {
|
|
21
|
+
const files = new Bun.Glob(`${pattern}/package.json`).scanSync({ cwd: repoRoot });
|
|
22
|
+
for (const file of files) {
|
|
23
|
+
const dir = `${repoRoot}/${file.replaceAll("\\", "/").slice(0, -13)}`;
|
|
24
|
+
try {
|
|
25
|
+
const { name } = await Bun.file(`${dir}/package.json`).json();
|
|
26
|
+
if (!name) continue;
|
|
27
|
+
const clientEntry = `${dir}/client/index.ts`;
|
|
28
|
+
if (existsSync(`${dir}/src`)) aliases[`${name}/src`] = `${dir}/src`;
|
|
29
|
+
if (existsSync(clientEntry)) aliases[`${name}/client`] = clientEntry;
|
|
30
|
+
aliases[name] = existsSync(clientEntry) ? clientEntry : `${dir}/src`;
|
|
31
|
+
} catch {}
|
|
32
|
+
}
|
|
33
|
+
}
|
|
34
|
+
return aliases;
|
|
35
|
+
}
|
|
36
|
+
const workspaceAliases = await collectWorkspaceAliases();
|
|
37
|
+
const runtimeShimPath = (workspaceAliases["@koishi-ce/components"] ?? "").replace(/client\/index\.ts$/, "client/schemastery-vue-runtime.ts");
|
|
38
|
+
/**
|
|
39
|
+
* 构建单个 webui 插件的前端产物。
|
|
40
|
+
*
|
|
41
|
+
* @param root 插件目录(无 `client/` 子目录时视为该插件没有前端,直接跳过)
|
|
42
|
+
* @param config 额外的 vite 配置,逐层合并覆盖下方默认值
|
|
43
|
+
*/
|
|
44
|
+
async function build(root, config = {}) {
|
|
45
|
+
if (!existsSync(`${root}/client`)) return;
|
|
46
|
+
const outDir = `${root}/dist`;
|
|
47
|
+
if (existsSync(outDir)) await rm(outDir, { recursive: true });
|
|
48
|
+
await mkdir(outDir, { recursive: true });
|
|
49
|
+
const results = await vite.build(vite.mergeConfig({
|
|
50
|
+
root,
|
|
51
|
+
build: {
|
|
52
|
+
write: false,
|
|
53
|
+
outDir: "dist",
|
|
54
|
+
assetsDir: "",
|
|
55
|
+
minify: true,
|
|
56
|
+
emptyOutDir: true,
|
|
57
|
+
commonjsOptions: { strictRequires: true },
|
|
58
|
+
lib: {
|
|
59
|
+
entry: `${root}/client/index.ts`,
|
|
60
|
+
fileName: "index",
|
|
61
|
+
formats: ["es"]
|
|
62
|
+
},
|
|
63
|
+
rollupOptions: {
|
|
64
|
+
makeAbsoluteExternalsRelative: true,
|
|
65
|
+
onwarn(warning, warn) {
|
|
66
|
+
if (warning.message.includes("is being imported multiple times")) return;
|
|
67
|
+
warn(warning);
|
|
68
|
+
},
|
|
69
|
+
external: [
|
|
70
|
+
"vue",
|
|
71
|
+
"vue-router",
|
|
72
|
+
"@vueuse/core",
|
|
73
|
+
"@koishi-ce/client"
|
|
74
|
+
],
|
|
75
|
+
output: { format: "iife" }
|
|
76
|
+
}
|
|
77
|
+
},
|
|
78
|
+
plugins: [
|
|
79
|
+
vue(),
|
|
80
|
+
yaml(),
|
|
81
|
+
(await import("unocss/vite")).default({ presets: [(await import("unocss/preset-mini")).default({ preflight: false })] })
|
|
82
|
+
],
|
|
83
|
+
resolve: { alias: {
|
|
84
|
+
...workspaceAliases,
|
|
85
|
+
"vue-i18n": "@koishi-ce/client",
|
|
86
|
+
"@koishi-ce/components": "@koishi-ce/client",
|
|
87
|
+
"@koishijs/components": workspaceAliases["@koishi-ce/components"],
|
|
88
|
+
"schemastery-vue/client": runtimeShimPath
|
|
89
|
+
} },
|
|
90
|
+
define: { "process.env.NODE_ENV": "\"production\"" }
|
|
91
|
+
}, config));
|
|
92
|
+
for (const item of results[0]?.output ?? []) {
|
|
93
|
+
const dest = `${root}/dist/${item.fileName === "index.mjs" ? "index.js" : item.fileName}`;
|
|
94
|
+
if (item.type === "asset") {
|
|
95
|
+
if (item.source === void 0) continue;
|
|
96
|
+
await Bun.write(dest, item.source);
|
|
97
|
+
} else if (item.code !== void 0) {
|
|
98
|
+
const { code } = await vite.minify(dest, item.code, {
|
|
99
|
+
compress: false,
|
|
100
|
+
mangle: false
|
|
101
|
+
});
|
|
102
|
+
await Bun.write(dest, code);
|
|
103
|
+
}
|
|
104
|
+
}
|
|
105
|
+
}
|
|
106
|
+
/**
|
|
107
|
+
* 创建开发模式下的 vite dev server(middlewareMode,不监听独立端口,
|
|
108
|
+
* 由宿主 HTTP 服务挂载到 `/vite/` 前缀下)。
|
|
109
|
+
*
|
|
110
|
+
* @param baseDir 用于圈定文件访问范围的工作区根目录
|
|
111
|
+
* @param config 额外的 vite 配置
|
|
112
|
+
* @returns vite 的 ViteDevServer 实例
|
|
113
|
+
*/
|
|
114
|
+
async function createServer(baseDir, config = {}) {
|
|
115
|
+
const root = resolve(import.meta.dir, "../app");
|
|
116
|
+
return vite.createServer(vite.mergeConfig({
|
|
117
|
+
root,
|
|
118
|
+
base: "/vite/",
|
|
119
|
+
server: {
|
|
120
|
+
middlewareMode: true,
|
|
121
|
+
fs: { allow: [vite.searchForWorkspaceRoot(baseDir)] }
|
|
122
|
+
},
|
|
123
|
+
plugins: [
|
|
124
|
+
vue(),
|
|
125
|
+
yaml(),
|
|
126
|
+
(await import("unocss/vite")).default({ presets: [(await import("unocss/preset-mini")).default({ preflight: false })] })
|
|
127
|
+
],
|
|
128
|
+
resolve: {
|
|
129
|
+
dedupe: [
|
|
130
|
+
"vue",
|
|
131
|
+
"vue-demi",
|
|
132
|
+
"vue-router",
|
|
133
|
+
"element-plus",
|
|
134
|
+
"@vueuse/core",
|
|
135
|
+
"@popperjs/core",
|
|
136
|
+
"marked",
|
|
137
|
+
"xss"
|
|
138
|
+
],
|
|
139
|
+
alias: {
|
|
140
|
+
"../client.js": "@koishi-ce/client",
|
|
141
|
+
"../vue.js": "vue",
|
|
142
|
+
"../vue-router.js": "vue-router",
|
|
143
|
+
"../vueuse.js": "@vueuse/core",
|
|
144
|
+
"schemastery-vue/client": runtimeShimPath
|
|
145
|
+
}
|
|
146
|
+
},
|
|
147
|
+
optimizeDeps: { include: [
|
|
148
|
+
"vue",
|
|
149
|
+
"vue-router",
|
|
150
|
+
"element-plus",
|
|
151
|
+
"@vueuse/core",
|
|
152
|
+
"@popperjs/core",
|
|
153
|
+
"marked",
|
|
154
|
+
"xss"
|
|
155
|
+
] },
|
|
156
|
+
build: { rollupOptions: { input: `${root}/index.html` } }
|
|
157
|
+
}, config));
|
|
158
|
+
}
|
|
159
|
+
//#endregion
|
|
160
|
+
export { createServer as n, build as t };
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
//#region src/yaml.ts
|
|
2
|
+
/**
|
|
3
|
+
* .yml/.yaml → JS 模块的 vite 转换插件(替代 @maikolib/vite-plugin-yaml)。
|
|
4
|
+
*
|
|
5
|
+
* 构建脚本统一以 Bun 执行,YAML 解析走 Bun 内置的 Bun.YAML,不再引入 js-yaml
|
|
6
|
+
* (其 4.1.0 版本存在 GHSA-52cp-r559-cp3m / GHSA-5p4m-2wfm-xmqj 高危通告)。
|
|
7
|
+
* 行为对齐原插件:默认导出解析结果,不产出 sourcemap 映射。
|
|
8
|
+
*/
|
|
9
|
+
function yaml() {
|
|
10
|
+
return {
|
|
11
|
+
name: "vite:transform-yaml",
|
|
12
|
+
transform(code, id) {
|
|
13
|
+
if (!/\.ya?ml$/.test(id)) return null;
|
|
14
|
+
const data = Bun.YAML.parse(code);
|
|
15
|
+
return {
|
|
16
|
+
code: `const data = ${JSON.stringify(data)};\nexport default data;`,
|
|
17
|
+
map: { mappings: "" }
|
|
18
|
+
};
|
|
19
|
+
}
|
|
20
|
+
};
|
|
21
|
+
}
|
|
22
|
+
//#endregion
|
|
23
|
+
export { yaml as t };
|
package/package.json
ADDED
|
@@ -0,0 +1,66 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "@koishi-ce/client",
|
|
3
|
+
"description": "Koishi Console Client",
|
|
4
|
+
"version": "1.0.0",
|
|
5
|
+
"type": "module",
|
|
6
|
+
"main": "client/index.ts",
|
|
7
|
+
"exports": {
|
|
8
|
+
".": {
|
|
9
|
+
"source": "./src/index.ts",
|
|
10
|
+
"default": "./client/index.ts"
|
|
11
|
+
},
|
|
12
|
+
"./global": "./global.d.ts",
|
|
13
|
+
"./bin": "./lib/bin.mjs",
|
|
14
|
+
"./lib": "./lib/index.mjs",
|
|
15
|
+
"./package.json": "./package.json"
|
|
16
|
+
},
|
|
17
|
+
"files": [
|
|
18
|
+
"app",
|
|
19
|
+
"client",
|
|
20
|
+
"lib",
|
|
21
|
+
"src",
|
|
22
|
+
"global.d.ts"
|
|
23
|
+
],
|
|
24
|
+
"bin": {
|
|
25
|
+
"koishi-console": "./lib/bin.mjs"
|
|
26
|
+
},
|
|
27
|
+
"contributors": [
|
|
28
|
+
"Shigma <shigma10826@gmail.com>",
|
|
29
|
+
"Oppenheymu <oppenheymu@gmail.com>"
|
|
30
|
+
],
|
|
31
|
+
"license": "AGPL-3.0",
|
|
32
|
+
"repository": {
|
|
33
|
+
"type": "git",
|
|
34
|
+
"url": "git+https://github.com/Koishi-CE/koishi.git",
|
|
35
|
+
"directory": "packages/web/client"
|
|
36
|
+
},
|
|
37
|
+
"bugs": {
|
|
38
|
+
"url": "https://github.com/Koishi-CE/koishi/issues"
|
|
39
|
+
},
|
|
40
|
+
"homepage": "https://koishi.chat",
|
|
41
|
+
"keywords": [
|
|
42
|
+
"bot",
|
|
43
|
+
"chatbot",
|
|
44
|
+
"koishi",
|
|
45
|
+
"plugin",
|
|
46
|
+
"webui",
|
|
47
|
+
"console",
|
|
48
|
+
"build"
|
|
49
|
+
],
|
|
50
|
+
"dependencies": {
|
|
51
|
+
"@koishi-ce/components": "^1.0.0",
|
|
52
|
+
"@satorijs/protocol": "^1.7.0",
|
|
53
|
+
"@vitejs/plugin-vue": "^6.0.8",
|
|
54
|
+
"@vueuse/core": "^14.4.0",
|
|
55
|
+
"cordis": "^3.18.1",
|
|
56
|
+
"cosmokit": "^1.8.1",
|
|
57
|
+
"element-plus": "^2.14.5",
|
|
58
|
+
"marked-vue": "^1.3.0",
|
|
59
|
+
"sass-embedded": "^1.102.0",
|
|
60
|
+
"unocss": "^66.8.1",
|
|
61
|
+
"vite": "^8.2.2",
|
|
62
|
+
"vue": "^3.5.42",
|
|
63
|
+
"vue-i18n": "^11.4.10",
|
|
64
|
+
"vue-router": "^5.2.0"
|
|
65
|
+
}
|
|
66
|
+
}
|
package/src/bin.ts
ADDED
|
@@ -0,0 +1,61 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* `koishi-console` CLI 入口(构建产物 lib/bin.mjs 由 package.json 的
|
|
5
|
+
* bin 字段指向,仓库内亦可用 Bun 直接运行本源文件)。
|
|
6
|
+
*
|
|
7
|
+
* 极简手写 CLI(不引 CLI 框架):仅 `build [root]` 一个子命令 +
|
|
8
|
+
* help/version。带 root(或 cwd 本身是含 client/ 的插件目录)时构建
|
|
9
|
+
* 该 webui 插件的前端;否则执行宿主控制台前端总装(scripts/client.ts,
|
|
10
|
+
* 产物写入 plugins/webui/console/dist)。
|
|
11
|
+
*/
|
|
12
|
+
|
|
13
|
+
import { existsSync } from "node:fs";
|
|
14
|
+
import { resolve } from "node:path";
|
|
15
|
+
import pkg from "../package.json" with { type: "json" };
|
|
16
|
+
|
|
17
|
+
const { version } = pkg;
|
|
18
|
+
|
|
19
|
+
import { build } from "./index.ts";
|
|
20
|
+
|
|
21
|
+
const help = `koishi-console/${version}
|
|
22
|
+
|
|
23
|
+
Usage:
|
|
24
|
+
$ koishi-console <command> [options]
|
|
25
|
+
|
|
26
|
+
Commands:
|
|
27
|
+
build [root] build the frontend of given webui plugin, or the host
|
|
28
|
+
console when omitted (or when cwd has no client/ dir)
|
|
29
|
+
|
|
30
|
+
Options:
|
|
31
|
+
-h, --help Display this message
|
|
32
|
+
-v, --version Display version number`;
|
|
33
|
+
|
|
34
|
+
async function main() {
|
|
35
|
+
const [command, ...args] = process.argv.slice(2);
|
|
36
|
+
if (command === undefined || command === "-h" || command === "--help") {
|
|
37
|
+
console.log(help);
|
|
38
|
+
return;
|
|
39
|
+
}
|
|
40
|
+
if (command === "-v" || command === "--version") {
|
|
41
|
+
console.log(`koishi-console/${version}`);
|
|
42
|
+
return;
|
|
43
|
+
}
|
|
44
|
+
if (command === "build") {
|
|
45
|
+
// root 缺省时:cwd 是插件目录则构建它,否则视为宿主总装
|
|
46
|
+
const root = args.find((arg) => !arg.startsWith("-"));
|
|
47
|
+
const target = root ?? (existsSync("client") ? "." : undefined);
|
|
48
|
+
if (target !== undefined) {
|
|
49
|
+
await build(resolve(process.cwd(), target));
|
|
50
|
+
return;
|
|
51
|
+
}
|
|
52
|
+
const host = await import("../scripts/client.ts");
|
|
53
|
+
await host.default();
|
|
54
|
+
return;
|
|
55
|
+
}
|
|
56
|
+
console.error(`Unknown command ${JSON.stringify(command)}.`);
|
|
57
|
+
console.log(help);
|
|
58
|
+
process.exitCode = 1;
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
await main();
|