@elevo-ai/create-plugin 0.1.5

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.
@@ -0,0 +1,2 @@
1
+ #!/usr/bin/env node
2
+ import "../src/index.js";
package/package.json ADDED
@@ -0,0 +1,22 @@
1
+ {
2
+ "name": "@elevo-ai/create-plugin",
3
+ "version": "0.1.5",
4
+ "description": "A CLI tool to create Elevo plugins",
5
+ "type": "module",
6
+ "bin": {
7
+ "create-plugin": "bin/create-plugin.js"
8
+ },
9
+ "files": [
10
+ "bin",
11
+ "src"
12
+ ],
13
+ "engines": {
14
+ "node": ">=20"
15
+ },
16
+ "author": "Elevo Team",
17
+ "license": "MIT",
18
+ "dependencies": {
19
+ "minimist": "^1.2.8",
20
+ "plop": "^4.0.5"
21
+ }
22
+ }
package/src/index.js ADDED
@@ -0,0 +1,30 @@
1
+ import path from "node:path";
2
+ import { fileURLToPath } from "node:url";
3
+ import minimist from "minimist";
4
+ import { Plop, run } from "plop";
5
+
6
+ const __dirname = path.dirname(fileURLToPath(import.meta.url));
7
+
8
+ const args = process.argv.slice(2);
9
+ const argv = minimist(args);
10
+
11
+ Plop.prepare(
12
+ {
13
+ cwd: argv.cwd,
14
+ configPath: path.join(__dirname, "plopfile.js"),
15
+ preload: argv.preload || [],
16
+ completion: argv.completion,
17
+ },
18
+ (env) =>
19
+ Plop.execute(env, (options) =>
20
+ run(
21
+ {
22
+ ...options,
23
+ // this will make the destination path to be based on the cwd when calling the wrapper
24
+ dest: process.cwd(),
25
+ },
26
+ undefined,
27
+ true
28
+ )
29
+ )
30
+ );
@@ -0,0 +1,160 @@
1
+ // @ts-check
2
+ const validPluginId = /^[a-z][a-z0-9]*(-[a-z0-9]+)*$/;
3
+
4
+ /** @type {import('plop').ActionType[]} */
5
+ const commonFiles = [
6
+ {
7
+ type: "addMany",
8
+ destination: "{{pluginId}}",
9
+ base: "templates/common",
10
+ templateFiles: "templates/common/**/*",
11
+ globOptions: {
12
+ dot: true,
13
+ },
14
+ },
15
+ ];
16
+
17
+ export default function (
18
+ /** @type {import('plop').NodePlopAPI} */
19
+ plop
20
+ ) {
21
+ plop.setPartial(
22
+ "pluginIdPascalCase",
23
+ "{{pascalCase pluginId}}"
24
+ );
25
+ plop.setPartial(
26
+ "pluginIdTitleCase",
27
+ "{{titleCase pluginId}}"
28
+ );
29
+
30
+ // create your generators here
31
+ plop.setGenerator("basics", {
32
+ prompts: [
33
+ {
34
+ type: "list",
35
+ name: "type",
36
+ message: "What type of plugin you want to create?",
37
+ choices: [
38
+ {
39
+ name: "Full App + AI Plugin",
40
+ value: "app-plus",
41
+ },
42
+ {
43
+ name: "UI Extension + AI Plugin",
44
+ value: "extension-plus",
45
+ },
46
+ {
47
+ name: "AI Plugin",
48
+ value: "plugin",
49
+ },
50
+ {
51
+ name: "Full App",
52
+ value: "app",
53
+ },
54
+ {
55
+ name: "UI Extension",
56
+ value: "extension",
57
+ },
58
+ ],
59
+ },
60
+ {
61
+ type: "input",
62
+ name: "pluginId",
63
+ message: "Your plugin id:",
64
+ validate(value) {
65
+ if (!validPluginId.test(value)) {
66
+ return "Please enter a lower-kebab-case plugin id.";
67
+ }
68
+ return true;
69
+ },
70
+ },
71
+ ],
72
+ actions(data) {
73
+ if (data?.type === "plugin") {
74
+ return [
75
+ ...commonFiles,
76
+ {
77
+ type: "addMany",
78
+ destination: "{{pluginId}}",
79
+ base: "templates/plugin",
80
+ templateFiles: "templates/plugin/**/*",
81
+ globOptions: {
82
+ dot: true,
83
+ },
84
+ },
85
+ ];
86
+ }
87
+
88
+ if (data?.type === "app" || data?.type === "extension") {
89
+ return [
90
+ ...commonFiles,
91
+ {
92
+ type: "addMany",
93
+ destination: "{{pluginId}}",
94
+ base: `templates/${data.type}`,
95
+ templateFiles: `templates/${data.type}/**/*`,
96
+ globOptions: {
97
+ dot: true,
98
+ },
99
+ },
100
+ {
101
+ type: "addMany",
102
+ destination: "{{pluginId}}/ui",
103
+ base: "templates/ui",
104
+ templateFiles: "templates/ui/**/*",
105
+ globOptions: {
106
+ dot: true,
107
+ },
108
+ },
109
+ ]
110
+ }
111
+
112
+ if (data?.type === "app-plus" || data?.type === "extension-plus") {
113
+ const mainType = data.type === "app-plus" ? "app" : "extension";
114
+ return [
115
+ ...commonFiles,
116
+ {
117
+ type: "addMany",
118
+ destination: "{{pluginId}}",
119
+ base: "templates/plugin",
120
+ templateFiles: "templates/plugin/**/*",
121
+ globOptions: {
122
+ dot: true,
123
+ },
124
+ },
125
+ {
126
+ type: "addMany",
127
+ destination: "{{pluginId}}",
128
+ base: `templates/${mainType}`,
129
+ templateFiles: `templates/${mainType}/**/*`,
130
+ force: true, // override the files from mainType if exists
131
+ globOptions: {
132
+ dot: true,
133
+ },
134
+ },
135
+ {
136
+ type: "addMany",
137
+ destination: "{{pluginId}}",
138
+ base: `templates/${data.type}`,
139
+ templateFiles: `templates/${data.type}/**/*`,
140
+ force: true, // override the files from mainType if exists
141
+ globOptions: {
142
+ dot: true,
143
+ },
144
+ },
145
+ {
146
+ type: "addMany",
147
+ destination: "{{pluginId}}/ui",
148
+ base: "templates/ui",
149
+ templateFiles: "templates/ui/**/*",
150
+ globOptions: {
151
+ dot: true,
152
+ },
153
+ },
154
+ ];
155
+ }
156
+
157
+ return [];
158
+ },
159
+ });
160
+ }
@@ -0,0 +1,29 @@
1
+ {
2
+ "name": "{{pluginId}}",
3
+ "version": "1.0.0",
4
+ "display_name": "{{>pluginIdTitleCase}}",
5
+ "description": "Please provide a description for your plugin.",
6
+ "type": "app",
7
+ "category": "extensions",
8
+ "author": {
9
+ "name": "Elevo Team",
10
+ "email": "dev@elevo.vip"
11
+ },
12
+ "keywords": [],
13
+
14
+ "capabilities": {
15
+ "ui": {
16
+ "has_interface": true,
17
+ "entry": "{{>pluginIdPascalCase}}",
18
+ "mode": "full",
19
+ "bundle": "ui/dist/app.umd.js"
20
+ }
21
+ },
22
+
23
+ "permissions": [
24
+ "workspace:read",
25
+ "workspace:write",
26
+ "conversation:read",
27
+ "conversation:write"
28
+ ]
29
+ }
@@ -0,0 +1,18 @@
1
+ import { useInjectCSS, usePluginSDK } from '@elevo-ai/plugin-sdk';
2
+ import { useTranslation } from 'react-i18next';
3
+ import './i18n';
4
+ import cssText from './globals.css?inline';
5
+
6
+ export function {{>pluginIdPascalCase}}() {
7
+ useInjectCSS(cssText);
8
+ const sdk = usePluginSDK();
9
+ const { t } = useTranslation('{{pluginId}}');
10
+
11
+ return (
12
+ <div id="{{pluginId}}">
13
+ <p>{t('{{pluginId}}')}</p>
14
+ </div>
15
+ );
16
+ }
17
+
18
+ export default {{>pluginIdPascalCase}};
@@ -0,0 +1,38 @@
1
+ {
2
+ "name": "{{pluginId}}",
3
+ "version": "1.0.0",
4
+ "display_name": "{{>pluginIdTitleCase}}",
5
+ "description": "Please provide a description for your plugin.",
6
+ "type": "app",
7
+ "category": "extensions",
8
+ "author": {
9
+ "name": "Elevo Team",
10
+ "email": "dev@elevo.vip"
11
+ },
12
+ "keywords": [],
13
+
14
+ "capabilities": {
15
+ "ui": {
16
+ "has_interface": true,
17
+ "entry": "{{>pluginIdPascalCase}}",
18
+ "mode": "full",
19
+ "bundle": "ui/dist/app.umd.js"
20
+ },
21
+ "prompts": {
22
+ "skills": [
23
+ "my-plugin-skill"
24
+ ],
25
+ "commands": [
26
+ "my-plugin-command"
27
+ ],
28
+ "agents": ["my-plugin-agent"]
29
+ }
30
+ },
31
+
32
+ "permissions": [
33
+ "workspace:read",
34
+ "workspace:write",
35
+ "conversation:read",
36
+ "conversation:write"
37
+ ]
38
+ }
@@ -0,0 +1,55 @@
1
+ # {{>pluginIdTitleCase}}
2
+
3
+ Please provide a description for your plugin.
4
+
5
+ ## 准备工作
6
+
7
+ 配置 npm registry,将 `@elevo-ai/*` 指向内部的 npm 仓库:
8
+
9
+ ```bash
10
+ npm config set @elevo:registry http://registry.npm.easyops.local
11
+ ```
12
+
13
+ ## 插件打包
14
+
15
+ 在插件根目录执行如下命令:
16
+
17
+ ```bash
18
+ npx @elevo-ai/plugin-bundle -y
19
+ ```
20
+
21
+ 打好的包在 `dist` 目录下。
22
+
23
+ ## UI 开发
24
+
25
+ 仅针对 Full App 和 UI Extension 类型的插件,才会包含 UI 相关的代码。
26
+
27
+ 首先,进入 ui 目录安装依赖:
28
+
29
+ ```bash
30
+ cd ui
31
+ npm install
32
+ ```
33
+
34
+ 打开两个终端,均进入 ui 目录,并分别启动开发构建和本地预览:
35
+
36
+ ```bash
37
+ # 1
38
+ cd ui
39
+ npm run dev
40
+
41
+ # 2
42
+ cd ui
43
+ npm run serve
44
+ ```
45
+
46
+ 然后即可打开浏览器访问 `http://localhost:3000`。
47
+
48
+ 命令一用于启动 Vite 开发服务器,监听文件变动并实时构建插件 UI 代码,构建产物会输出到 `ui/dist` 目录;命令二用于启动一个本地服务器,监听 `http://localhost:3000`,用于预览插件在远端主应用中的效果,所有非插件的请求均会透传到远端公共服务器上。
49
+
50
+ 默认的远端公共服务器为 `https://172.30.0.188.nip.io`,可以按需修改,例如:
51
+
52
+ ```bash
53
+ # 启动插件开发服务器,指定远端主应用地址
54
+ npm run serve -- --server=https://my-elevo-instance.com
55
+ ```
@@ -0,0 +1,29 @@
1
+ {
2
+ "name": "{{pluginId}}",
3
+ "version": "1.0.0",
4
+ "display_name": "{{>pluginIdTitleCase}}",
5
+ "description": "Please provide a description for your plugin.",
6
+ "type": "app",
7
+ "category": "extensions",
8
+ "author": {
9
+ "name": "Elevo Team",
10
+ "email": "dev@elevo.vip"
11
+ },
12
+ "keywords": [],
13
+
14
+ "capabilities": {
15
+ "ui": {
16
+ "has_interface": true,
17
+ "entry": "{{>pluginIdPascalCase}}",
18
+ "mode": "extension",
19
+ "bundle": "ui/dist/app.umd.js"
20
+ }
21
+ },
22
+
23
+ "permissions": [
24
+ "workspace:read",
25
+ "workspace:write",
26
+ "conversation:read",
27
+ "conversation:write"
28
+ ]
29
+ }
@@ -0,0 +1,38 @@
1
+ import { Gauge } from 'lucide-react';
2
+ import { useInjectCSS, usePluginSDK, type ElevoPluginContributes } from '@elevo-ai/plugin-sdk';
3
+ import { useTranslation } from 'react-i18next';
4
+ import './i18n';
5
+ import cssText from './globals.css?inline';
6
+
7
+ export function {{>pluginIdPascalCase}}() {
8
+ // This function will not be called
9
+ return null;
10
+ }
11
+
12
+ function MyPluginView() {
13
+ useInjectCSS(cssText);
14
+ const sdk = usePluginSDK();
15
+ const { t } = useTranslation('{{pluginId}}');
16
+
17
+ return (
18
+ <div id="{{pluginId}}">
19
+ <p>{t('{{pluginId}}')}</p>
20
+ </div>
21
+ );
22
+ }
23
+
24
+ const contributes: ElevoPluginContributes = {
25
+ sidebar: {
26
+ menuItems: [
27
+ {
28
+ id: "{{pluginId}}-view",
29
+ labelKey: "{{pluginId}}.sidebar.view",
30
+ defaultLabel: "Dashboard",
31
+ icon: Gauge,
32
+ view: MyPluginView,
33
+ },
34
+ ],
35
+ },
36
+ };
37
+
38
+ export default {{>pluginIdPascalCase}};
@@ -0,0 +1,38 @@
1
+ {
2
+ "name": "{{pluginId}}",
3
+ "version": "1.0.0",
4
+ "display_name": "{{>pluginIdTitleCase}}",
5
+ "description": "Please provide a description for your plugin.",
6
+ "type": "app",
7
+ "category": "extensions",
8
+ "author": {
9
+ "name": "Elevo Team",
10
+ "email": "dev@elevo.vip"
11
+ },
12
+ "keywords": [],
13
+
14
+ "capabilities": {
15
+ "ui": {
16
+ "has_interface": true,
17
+ "entry": "{{>pluginIdPascalCase}}",
18
+ "mode": "extension",
19
+ "bundle": "ui/dist/app.umd.js"
20
+ },
21
+ "prompts": {
22
+ "skills": [
23
+ "my-plugin-skill"
24
+ ],
25
+ "commands": [
26
+ "my-plugin-command"
27
+ ],
28
+ "agents": ["my-plugin-agent"]
29
+ }
30
+ },
31
+
32
+ "permissions": [
33
+ "workspace:read",
34
+ "workspace:write",
35
+ "conversation:read",
36
+ "conversation:write"
37
+ ]
38
+ }
@@ -0,0 +1,9 @@
1
+ {
2
+ "name": "{{pluginId}}",
3
+ "version": "1.0.0",
4
+ "description": "Please provide a description for your plugin.",
5
+ "author": {
6
+ "name": "Elevo Team",
7
+ "email": "dev@elevo.vip"
8
+ }
9
+ }
@@ -0,0 +1,9 @@
1
+ ---
2
+ name: my-plugin-agent
3
+ description: Please enter a description for My Plugin Agent
4
+ color: purple
5
+ ---
6
+
7
+ # My Plugin Agent
8
+
9
+ You are a helpful assistant.