create-donobu-plugin 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/index.js +307 -0
- package/package.json +24 -0
package/index.js
ADDED
|
@@ -0,0 +1,307 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
|
|
3
|
+
import { mkdir, writeFile, readFile } from "fs/promises";
|
|
4
|
+
import { join, dirname } from "path";
|
|
5
|
+
import { createRequire } from "module";
|
|
6
|
+
|
|
7
|
+
async function getDonobuVersions() {
|
|
8
|
+
try {
|
|
9
|
+
// Find the donobu package.json by resolving the module path
|
|
10
|
+
const require = createRequire(import.meta.url);
|
|
11
|
+
const donobuPath = require.resolve("donobu");
|
|
12
|
+
// Navigate up to find package.json (donobu path might point to dist/main.js)
|
|
13
|
+
const donobuDir = dirname(donobuPath);
|
|
14
|
+
let packageJsonPath = join(donobuDir, "package.json");
|
|
15
|
+
|
|
16
|
+
try {
|
|
17
|
+
await readFile(packageJsonPath, "utf8");
|
|
18
|
+
} catch {
|
|
19
|
+
// If not found, try going up one more directory
|
|
20
|
+
packageJsonPath = join(dirname(donobuDir), "package.json");
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
const packageJsonContent = await readFile(packageJsonPath, "utf8");
|
|
24
|
+
const donobuPackageJson = JSON.parse(packageJsonContent);
|
|
25
|
+
|
|
26
|
+
return {
|
|
27
|
+
donobuVersion: donobuPackageJson.version,
|
|
28
|
+
playwrightVersion:
|
|
29
|
+
donobuPackageJson.devDependencies?.playwright ||
|
|
30
|
+
donobuPackageJson.dependencies?.playwright ||
|
|
31
|
+
donobuPackageJson.peerDependencies?.playwright?.replace(/^>=/, "") ||
|
|
32
|
+
"1.53.2",
|
|
33
|
+
playwrightTestVersion:
|
|
34
|
+
donobuPackageJson.devDependencies?.["@playwright/test"] ||
|
|
35
|
+
donobuPackageJson.dependencies?.["@playwright/test"] ||
|
|
36
|
+
donobuPackageJson.peerDependencies?.["@playwright/test"]?.replace(
|
|
37
|
+
/^>=/,
|
|
38
|
+
""
|
|
39
|
+
) ||
|
|
40
|
+
"1.53.2",
|
|
41
|
+
};
|
|
42
|
+
} catch (error) {
|
|
43
|
+
console.error("Could not read the Donobu package.json file!");
|
|
44
|
+
throw error;
|
|
45
|
+
}
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
async function createPluginStructure(pluginName) {
|
|
49
|
+
const pluginDir = join(process.cwd(), pluginName);
|
|
50
|
+
console.log(`Creating plugin directory: ${pluginDir}`);
|
|
51
|
+
// Get current donobu and playwright versions
|
|
52
|
+
const versions = await getDonobuVersions();
|
|
53
|
+
console.log(`Using Donobu version: ${versions.donobuVersion}`);
|
|
54
|
+
console.log(`Using Playwright version: ${versions.playwrightVersion}`);
|
|
55
|
+
// Create directory structure
|
|
56
|
+
await mkdir(pluginDir, { recursive: true });
|
|
57
|
+
await mkdir(join(pluginDir, "src"), { recursive: true });
|
|
58
|
+
console.log("Creating files...");
|
|
59
|
+
await createTemplateFiles(pluginDir, pluginName, versions);
|
|
60
|
+
console.log(`\nPlugin "${pluginName}" created successfully!`);
|
|
61
|
+
console.log(`\nNext steps:`);
|
|
62
|
+
console.log(` cd ${pluginName}`);
|
|
63
|
+
console.log(` npm install`);
|
|
64
|
+
console.log(` # Edit src/index.ts to add your custom tools`);
|
|
65
|
+
console.log(` npx install-donobu-plugin`);
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
async function createTemplateFiles(pluginDir, pluginName, versions) {
|
|
69
|
+
// Create package.json
|
|
70
|
+
const packageJson = {
|
|
71
|
+
name: pluginName,
|
|
72
|
+
version: "1.0.0",
|
|
73
|
+
private: true,
|
|
74
|
+
type: "module",
|
|
75
|
+
description: "Custom tools for use by Donobu.",
|
|
76
|
+
main: "./dist/index.mjs",
|
|
77
|
+
types: "./dist/index.d.ts",
|
|
78
|
+
exports: {
|
|
79
|
+
".": "./dist/index.mjs",
|
|
80
|
+
},
|
|
81
|
+
files: ["dist"],
|
|
82
|
+
scripts: {
|
|
83
|
+
clean: "rm -rf dist",
|
|
84
|
+
build:
|
|
85
|
+
"npm run clean && npm install && tsc -p tsconfig.json && node esbuild.config.mjs",
|
|
86
|
+
},
|
|
87
|
+
license: "UNLICENSED",
|
|
88
|
+
devDependencies: {
|
|
89
|
+
donobu: `^${versions.donobuVersion}`,
|
|
90
|
+
playwright: versions.playwrightVersion,
|
|
91
|
+
"@playwright/test": versions.playwrightTestVersion,
|
|
92
|
+
typescript: "^5.8.3",
|
|
93
|
+
esbuild: "^0.25.6",
|
|
94
|
+
},
|
|
95
|
+
peerDependencies: {
|
|
96
|
+
donobu: `>=${versions.donobuVersion}`,
|
|
97
|
+
playwright: `>=${versions.playwrightVersion}`,
|
|
98
|
+
"@playwright/test": `>=${versions.playwrightTestVersion}`,
|
|
99
|
+
},
|
|
100
|
+
peerDependenciesMeta: {
|
|
101
|
+
playwright: {
|
|
102
|
+
optional: false,
|
|
103
|
+
},
|
|
104
|
+
"@playwright/test": {
|
|
105
|
+
optional: false,
|
|
106
|
+
},
|
|
107
|
+
},
|
|
108
|
+
dependencies: {
|
|
109
|
+
zod: "^3.24.1",
|
|
110
|
+
},
|
|
111
|
+
};
|
|
112
|
+
|
|
113
|
+
await writeFile(
|
|
114
|
+
join(pluginDir, "package.json"),
|
|
115
|
+
JSON.stringify(packageJson, null, 2)
|
|
116
|
+
);
|
|
117
|
+
|
|
118
|
+
// Create tsconfig.json
|
|
119
|
+
const tsConfig = {
|
|
120
|
+
compilerOptions: {
|
|
121
|
+
target: "ES2020",
|
|
122
|
+
module: "NodeNext",
|
|
123
|
+
moduleResolution: "NodeNext",
|
|
124
|
+
rootDir: "./src",
|
|
125
|
+
outDir: "./dist",
|
|
126
|
+
declaration: true,
|
|
127
|
+
strict: true,
|
|
128
|
+
esModuleInterop: true,
|
|
129
|
+
skipLibCheck: true,
|
|
130
|
+
forceConsistentCasingInFileNames: true,
|
|
131
|
+
},
|
|
132
|
+
include: ["src/**/*"],
|
|
133
|
+
};
|
|
134
|
+
|
|
135
|
+
await writeFile(
|
|
136
|
+
join(pluginDir, "tsconfig.json"),
|
|
137
|
+
JSON.stringify(tsConfig, null, 2)
|
|
138
|
+
);
|
|
139
|
+
|
|
140
|
+
// Create esbuild.config.mjs
|
|
141
|
+
const esbuildConfig = `import { build } from 'esbuild';
|
|
142
|
+
|
|
143
|
+
await build({
|
|
144
|
+
entryPoints: ['dist/index.js'],
|
|
145
|
+
outfile: 'dist/index.mjs',
|
|
146
|
+
bundle: true,
|
|
147
|
+
format: 'esm',
|
|
148
|
+
platform: 'node',
|
|
149
|
+
external: ['donobu', 'playwright'],
|
|
150
|
+
minify: true,
|
|
151
|
+
});
|
|
152
|
+
`;
|
|
153
|
+
|
|
154
|
+
await writeFile(join(pluginDir, "esbuild.config.mjs"), esbuildConfig);
|
|
155
|
+
|
|
156
|
+
// Create src/index.ts
|
|
157
|
+
const indexTs = `import type { Tool } from "donobu";
|
|
158
|
+
import { PluginDependencies } from "./PluginDependencies.js";
|
|
159
|
+
|
|
160
|
+
export async function loadCustomTools(
|
|
161
|
+
dependencies: PluginDependencies
|
|
162
|
+
): Promise<Tool<any, any>[]> {
|
|
163
|
+
// Register your custom tools here.
|
|
164
|
+
return [];
|
|
165
|
+
}
|
|
166
|
+
`;
|
|
167
|
+
|
|
168
|
+
await writeFile(join(pluginDir, "src", "index.ts"), indexTs);
|
|
169
|
+
|
|
170
|
+
// Create src/createTool.ts
|
|
171
|
+
const createToolTs = `import { z } from "zod";
|
|
172
|
+
import type { ToolCallContext, ToolCallResult, Tool } from "donobu";
|
|
173
|
+
import { PluginDependencies } from "./PluginDependencies.js";
|
|
174
|
+
|
|
175
|
+
/**
|
|
176
|
+
* Factory function to create a Donobu Tool instance.
|
|
177
|
+
*/
|
|
178
|
+
export function createTool<
|
|
179
|
+
CallSchema extends z.ZodObject<any>,
|
|
180
|
+
CallFromGptSchema extends z.ZodObject<any> = CallSchema,
|
|
181
|
+
>(
|
|
182
|
+
dependencies: PluginDependencies,
|
|
183
|
+
options: CreateToolOptions<CallSchema, CallFromGptSchema>
|
|
184
|
+
): Tool<CallSchema, CallFromGptSchema> {
|
|
185
|
+
class AnonymousTool extends dependencies.donobu.Tool<
|
|
186
|
+
CallSchema,
|
|
187
|
+
CallFromGptSchema
|
|
188
|
+
> {
|
|
189
|
+
public constructor() {
|
|
190
|
+
super(
|
|
191
|
+
options.name,
|
|
192
|
+
options.description,
|
|
193
|
+
options.schema,
|
|
194
|
+
(options.gptSchema ?? options.schema) as CallFromGptSchema,
|
|
195
|
+
options.requiresGpt
|
|
196
|
+
);
|
|
197
|
+
}
|
|
198
|
+
public override async call(
|
|
199
|
+
ctx: ToolCallContext,
|
|
200
|
+
params: z.infer<CallSchema>
|
|
201
|
+
): Promise<ToolCallResult> {
|
|
202
|
+
return options.call(ctx, params);
|
|
203
|
+
}
|
|
204
|
+
public override async callFromGpt(
|
|
205
|
+
ctx: ToolCallContext,
|
|
206
|
+
params: z.infer<CallFromGptSchema>
|
|
207
|
+
): Promise<ToolCallResult> {
|
|
208
|
+
return options.callFromGpt
|
|
209
|
+
? options.callFromGpt(ctx, params)
|
|
210
|
+
: this.call(ctx, params);
|
|
211
|
+
}
|
|
212
|
+
}
|
|
213
|
+
|
|
214
|
+
return new AnonymousTool();
|
|
215
|
+
}
|
|
216
|
+
|
|
217
|
+
export interface CreateToolOptions<
|
|
218
|
+
CallSchema extends z.ZodObject<any>,
|
|
219
|
+
CallFromGptSchema extends z.ZodObject<any> = CallSchema,
|
|
220
|
+
> {
|
|
221
|
+
/**
|
|
222
|
+
* @param name This is the name for the tool that will be shared with the LLM when making requests.
|
|
223
|
+
* @param description This is the description that will be shared with the LLM when making requests.
|
|
224
|
+
* @param inputSchema This is the JSON-schema for the tool when it is invoked by a non-LLM.
|
|
225
|
+
* @param inputSchemaForGpt This is the JSON-schema that will be shared with the LLM when making
|
|
226
|
+
* requests during autonomous flows.
|
|
227
|
+
* @param requiresGpt Set to true if this tool requires the usage of a GPT.
|
|
228
|
+
* @param call This is the function that will be invoked when the tool is called by a non-LLM.
|
|
229
|
+
* @param callFromGpt This is the function that will be invoked when the tool is called by an LLM.
|
|
230
|
+
*/
|
|
231
|
+
name: string;
|
|
232
|
+
description: string;
|
|
233
|
+
requiresGpt: boolean;
|
|
234
|
+
schema: CallSchema;
|
|
235
|
+
gptSchema?: CallFromGptSchema;
|
|
236
|
+
call(
|
|
237
|
+
ctx: ToolCallContext,
|
|
238
|
+
params: z.infer<CallSchema>
|
|
239
|
+
): Promise<ToolCallResult> | ToolCallResult;
|
|
240
|
+
callFromGpt?(
|
|
241
|
+
ctx: ToolCallContext,
|
|
242
|
+
params: z.infer<CallFromGptSchema>
|
|
243
|
+
): Promise<ToolCallResult> | ToolCallResult;
|
|
244
|
+
}
|
|
245
|
+
`;
|
|
246
|
+
|
|
247
|
+
await writeFile(join(pluginDir, "src", "createTool.ts"), createToolTs);
|
|
248
|
+
|
|
249
|
+
// Create src/PluginDependencies.ts
|
|
250
|
+
const pluginDepsTs = `export interface PluginDependencies {
|
|
251
|
+
donobu: typeof import("donobu");
|
|
252
|
+
playwright: typeof import("playwright");
|
|
253
|
+
}
|
|
254
|
+
`;
|
|
255
|
+
|
|
256
|
+
await writeFile(
|
|
257
|
+
join(pluginDir, "src", "PluginDependencies.ts"),
|
|
258
|
+
pluginDepsTs
|
|
259
|
+
);
|
|
260
|
+
|
|
261
|
+
// Create a basic README
|
|
262
|
+
const readme = `# ${pluginName}
|
|
263
|
+
|
|
264
|
+
A custom Donobu plugin with tools for browser automation.
|
|
265
|
+
|
|
266
|
+
## Development
|
|
267
|
+
|
|
268
|
+
1. Edit \`src/index.ts\` to add your custom tools
|
|
269
|
+
2. Build and install the plugin:
|
|
270
|
+
\`\`\`bash
|
|
271
|
+
npm run build
|
|
272
|
+
npm exec install-donobu-plugin
|
|
273
|
+
\`\`\`
|
|
274
|
+
3. Restart Donobu to see your tools
|
|
275
|
+
`;
|
|
276
|
+
|
|
277
|
+
await writeFile(join(pluginDir, "README.md"), readme);
|
|
278
|
+
}
|
|
279
|
+
|
|
280
|
+
async function main() {
|
|
281
|
+
const pluginName = process.argv[2];
|
|
282
|
+
|
|
283
|
+
if (!pluginName) {
|
|
284
|
+
console.error("Usage: create-donobu-plugin <plugin-name>");
|
|
285
|
+
console.error("");
|
|
286
|
+
console.error("Example:");
|
|
287
|
+
console.error(" npm create donobu-plugin my-awesome-plugin");
|
|
288
|
+
process.exit(1);
|
|
289
|
+
}
|
|
290
|
+
|
|
291
|
+
// Validate plugin name
|
|
292
|
+
if (!/^[a-z0-9-_]+$/.test(pluginName)) {
|
|
293
|
+
console.error(
|
|
294
|
+
"Plugin name must contain only lowercase letters, numbers, hyphens, and underscores"
|
|
295
|
+
);
|
|
296
|
+
process.exit(1);
|
|
297
|
+
}
|
|
298
|
+
|
|
299
|
+
try {
|
|
300
|
+
await createPluginStructure(pluginName);
|
|
301
|
+
} catch (error) {
|
|
302
|
+
console.error("Failed to create plugin:", error.message);
|
|
303
|
+
process.exit(1);
|
|
304
|
+
}
|
|
305
|
+
}
|
|
306
|
+
|
|
307
|
+
main();
|
package/package.json
ADDED
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "create-donobu-plugin",
|
|
3
|
+
"version": "1.0.0",
|
|
4
|
+
"type": "module",
|
|
5
|
+
"description": "Create a new Donobu plugin",
|
|
6
|
+
"author": "Donobu",
|
|
7
|
+
"homepage": "https://donobu.com",
|
|
8
|
+
"main": "index.js",
|
|
9
|
+
"bin": {
|
|
10
|
+
"create-donobu-plugin": "./index.js"
|
|
11
|
+
},
|
|
12
|
+
"files": [
|
|
13
|
+
"index.js"
|
|
14
|
+
],
|
|
15
|
+
"dependencies": {
|
|
16
|
+
"donobu": "^2.30.1"
|
|
17
|
+
},
|
|
18
|
+
"keywords": [
|
|
19
|
+
"donobu",
|
|
20
|
+
"plugin",
|
|
21
|
+
"create"
|
|
22
|
+
],
|
|
23
|
+
"license": "UNLICENSED"
|
|
24
|
+
}
|