create-openclaw-plugin 0.1.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.
Files changed (2) hide show
  1. package/bin/create.js +249 -0
  2. package/package.json +13 -0
package/bin/create.js ADDED
@@ -0,0 +1,249 @@
1
+ #!/usr/bin/env node
2
+
3
+ const fs = require("fs");
4
+ const path = require("path");
5
+
6
+ // ---- 颜色 ----
7
+ const green = (s) => `\x1b[32m${s}\x1b[0m`;
8
+ const cyan = (s) => `\x1b[36m${s}\x1b[0m`;
9
+ const yellow = (s) => `\x1b[33m${s}\x1b[0m`;
10
+ const bold = (s) => `\x1b[1m${s}\x1b[0m`;
11
+
12
+ // ---- 参数解析 ----
13
+ const args = process.argv.slice(2);
14
+ if (args.length === 0 || args[0] === "--help" || args[0] === "-h") {
15
+ console.log(`
16
+ ${bold("create-openclaw-plugin")} — 一键创建 OpenClaw Plugin 项目
17
+
18
+ ${bold("用法:")}
19
+ npx create-openclaw-plugin ${cyan("<plugin-name>")}
20
+
21
+ ${bold("示例:")}
22
+ npx create-openclaw-plugin my-weather-plugin
23
+ npx create-openclaw-plugin openclaw-plugin-translator
24
+
25
+ ${bold("生成结构:")}
26
+ <plugin-name>/
27
+ ├── src/index.ts # 插件源码(含示例 Tool)
28
+ ├── openclaw.plugin.json # 插件清单
29
+ ├── package.json # npm 包描述
30
+ ├── tsconfig.json # TypeScript 配置
31
+ ├── tsup.config.ts # 构建配置
32
+ └── README.md # 说明文档
33
+ `);
34
+ process.exit(0);
35
+ }
36
+
37
+ const projectName = args[0];
38
+ const projectDir = path.resolve(process.cwd(), projectName);
39
+
40
+ // 插件 ID:如果名字已经带 openclaw-plugin- 前缀就直接用,否则加上
41
+ const pluginId = projectName.startsWith("openclaw-plugin-")
42
+ ? projectName
43
+ : `openclaw-plugin-${projectName}`;
44
+
45
+ // Tool name: 把 - 转 _,去掉 openclaw-plugin- 前缀
46
+ const toolBaseName = pluginId
47
+ .replace("openclaw-plugin-", "")
48
+ .replace(/-/g, "_");
49
+ const toolName = `${toolBaseName}_hello`;
50
+
51
+ // ---- 检查目录 ----
52
+ if (fs.existsSync(projectDir)) {
53
+ console.error(`\n❌ 目录已存在: ${projectDir}\n`);
54
+ process.exit(1);
55
+ }
56
+
57
+ // ---- 模板文件 ----
58
+ const templates = {
59
+ "package.json": JSON.stringify(
60
+ {
61
+ name: pluginId,
62
+ version: "0.1.0",
63
+ description: `OpenClaw plugin: ${pluginId}`,
64
+ type: "commonjs",
65
+ main: "dist/index.js",
66
+ types: "dist/index.d.ts",
67
+ openclaw: {
68
+ id: pluginId,
69
+ extensions: ["./dist/index.js"],
70
+ },
71
+ scripts: {
72
+ build: "tsup",
73
+ dev: "tsup --watch",
74
+ },
75
+ peerDependencies: {
76
+ openclaw: ">=2026.3.22",
77
+ },
78
+ devDependencies: {
79
+ openclaw: "^2026.3.22",
80
+ tsup: "^8.5.1",
81
+ typescript: "^5.7.0",
82
+ "@sinclair/typebox": "^0.34.0",
83
+ },
84
+ engines: { node: ">=18.0.0" },
85
+ files: ["dist", "openclaw.plugin.json", "package.json", "README.md"],
86
+ license: "MIT",
87
+ },
88
+ null,
89
+ 2
90
+ ),
91
+
92
+ "openclaw.plugin.json": JSON.stringify(
93
+ {
94
+ id: pluginId,
95
+ configSchema: {
96
+ type: "object",
97
+ additionalProperties: false,
98
+ properties: {},
99
+ },
100
+ },
101
+ null,
102
+ 2
103
+ ),
104
+
105
+ "tsup.config.ts": `import { defineConfig } from "tsup";
106
+ export default defineConfig({
107
+ entry: ["src/index.ts"],
108
+ format: ["cjs"],
109
+ target: "node18",
110
+ dts: true,
111
+ clean: true,
112
+ external: ["openclaw"],
113
+ sourcemap: true,
114
+ });
115
+ `,
116
+
117
+ "tsconfig.json": JSON.stringify(
118
+ {
119
+ compilerOptions: {
120
+ target: "ES2022",
121
+ module: "ESNext",
122
+ moduleResolution: "bundler",
123
+ esModuleInterop: true,
124
+ strict: true,
125
+ outDir: "dist",
126
+ declaration: true,
127
+ skipLibCheck: true,
128
+ },
129
+ include: ["src"],
130
+ },
131
+ null,
132
+ 2
133
+ ),
134
+
135
+ "src/index.ts": `/**
136
+ * ${pluginId}
137
+ *
138
+ * TODO: Replace this demo tool with your own implementation.
139
+ */
140
+
141
+ import { definePluginEntry } from "openclaw/plugin-sdk/plugin-entry";
142
+ import type { AnyAgentTool } from "openclaw/plugin-sdk/plugin-entry";
143
+ import type { OpenClawPluginToolContext } from "openclaw/plugin-sdk/core";
144
+ import { Type } from "@sinclair/typebox";
145
+
146
+ // ---------------------------------------------------------------------------
147
+ // Tool definition
148
+ // ---------------------------------------------------------------------------
149
+
150
+ function createHelloTool(): AnyAgentTool {
151
+ return {
152
+ name: "${toolName}",
153
+ label: "${toolBaseName} Hello",
154
+ description:
155
+ "A demo tool from ${pluginId}. Returns a greeting message. " +
156
+ "Replace this with your own tool implementation.",
157
+ parameters: Type.Object({
158
+ name: Type.Optional(
159
+ Type.String({ description: "Name to greet. Defaults to 'World'." })
160
+ ),
161
+ }),
162
+ async execute(_toolCallId, params) {
163
+ const greeting = \`Hello, \${params.name || "World"}! 👋 from ${pluginId}\`;
164
+ return {
165
+ content: [{ type: "text", text: greeting }],
166
+ details: { greeting },
167
+ };
168
+ },
169
+ };
170
+ }
171
+
172
+ // ---------------------------------------------------------------------------
173
+ // Tool factory
174
+ // ---------------------------------------------------------------------------
175
+
176
+ function helloToolFactory(_ctx: OpenClawPluginToolContext): AnyAgentTool {
177
+ // Read config if needed:
178
+ // const config = _ctx.config?.plugins?.entries?.["${pluginId}"]?.config;
179
+ return createHelloTool();
180
+ }
181
+
182
+ // ---------------------------------------------------------------------------
183
+ // Plugin entry
184
+ // ---------------------------------------------------------------------------
185
+
186
+ export default definePluginEntry({
187
+ id: "${pluginId}",
188
+ name: "${pluginId}",
189
+ description: "TODO: Add your plugin description here.",
190
+
191
+ register(api) {
192
+ api.registerTool(helloToolFactory, {
193
+ name: "${toolName}",
194
+ });
195
+
196
+ api.logger.info("✅ ${pluginId} loaded");
197
+ },
198
+ });
199
+ `,
200
+
201
+ "README.md": `# ${pluginId}
202
+
203
+ An OpenClaw plugin.
204
+
205
+ ## Quick Start
206
+
207
+ \`\`\`bash
208
+ npm install
209
+ npm run build
210
+ openclaw plugins install .
211
+ openclaw gateway restart
212
+ \`\`\`
213
+
214
+ ## Development
215
+
216
+ \`\`\`bash
217
+ # Edit src/index.ts, then:
218
+ npm run build
219
+ cp -rf dist openclaw.plugin.json package.json ~/.openclaw/extensions/${pluginId}/
220
+ openclaw gateway restart
221
+ \`\`\`
222
+ `,
223
+ };
224
+
225
+ // ---- 写文件 ----
226
+ console.log(`\n🔌 Creating OpenClaw plugin: ${bold(pluginId)}\n`);
227
+
228
+ fs.mkdirSync(path.join(projectDir, "src"), { recursive: true });
229
+
230
+ for (const [filePath, content] of Object.entries(templates)) {
231
+ const fullPath = path.join(projectDir, filePath);
232
+ fs.writeFileSync(fullPath, content, "utf-8");
233
+ console.log(` ${green("✓")} ${filePath}`);
234
+ }
235
+
236
+ // ---- 完成提示 ----
237
+ console.log(`
238
+ ${green("✅ Done!")} Plugin created at ${cyan(projectDir)}
239
+
240
+ ${bold("Next steps:")}
241
+
242
+ cd ${projectName}
243
+ npm install
244
+ npm run build
245
+ openclaw plugins install .
246
+ openclaw gateway restart
247
+
248
+ ${yellow("📝 记得修改 src/index.ts 中的 demo tool 为你自己的实现!")}
249
+ `);
package/package.json ADDED
@@ -0,0 +1,13 @@
1
+ {
2
+ "name": "create-openclaw-plugin",
3
+ "version": "0.1.0",
4
+ "description": "Scaffold a new OpenClaw plugin in seconds",
5
+ "bin": {
6
+ "create-openclaw-plugin": "./bin/create.js"
7
+ },
8
+ "files": ["bin", "template"],
9
+ "license": "MIT",
10
+ "engines": {
11
+ "node": ">=18.0.0"
12
+ }
13
+ }