@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.
- package/bin/create-plugin.js +2 -0
- package/package.json +22 -0
- package/src/index.js +30 -0
- package/src/plopfile.js +160 -0
- package/src/templates/app/elevo.plugin.json +29 -0
- package/src/templates/app/ui/src/App.tsx.hbs +18 -0
- package/src/templates/app-plus/elevo.plugin.json +38 -0
- package/src/templates/common/README.md +55 -0
- package/src/templates/extension/elevo.plugin.json +29 -0
- package/src/templates/extension/ui/src/App.tsx.hbs +38 -0
- package/src/templates/extension-plus/elevo.plugin.json +38 -0
- package/src/templates/plugin/.claude-plugin/plugin.json +9 -0
- package/src/templates/plugin/agents/my-plugin-agent.md +9 -0
- package/src/templates/plugin/commands/my-plugin-command.md +946 -0
- package/src/templates/plugin/elevo.plugin.json +34 -0
- package/src/templates/plugin/skills/my-plugin-skill/SKILL.md +6 -0
- package/src/templates/ui/package.json.hbs +31 -0
- package/src/templates/ui/src/globals.css +5 -0
- package/src/templates/ui/src/i18n.ts +17 -0
- package/src/templates/ui/src/vite-env.d.ts +1 -0
- package/src/templates/ui/tailwind.config.js +5 -0
- package/src/templates/ui/tsconfig.json +21 -0
- package/src/templates/ui/vite.config.ts +6 -0
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
|
+
);
|
package/src/plopfile.js
ADDED
|
@@ -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
|
+
}
|