@evermore.work/create-evermore-plugin 2026.509.0-canary.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/README.md +52 -0
- package/dist/index.d.ts +24 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +622 -0
- package/dist/index.js.map +1 -0
- package/package.json +43 -0
package/README.md
ADDED
|
@@ -0,0 +1,52 @@
|
|
|
1
|
+
# @evermore.work/create-evermore-plugin
|
|
2
|
+
|
|
3
|
+
Scaffolding tool for creating new Evermore plugins.
|
|
4
|
+
|
|
5
|
+
```bash
|
|
6
|
+
npx @evermore.work/create-evermore-plugin my-plugin
|
|
7
|
+
```
|
|
8
|
+
|
|
9
|
+
Or with options:
|
|
10
|
+
|
|
11
|
+
```bash
|
|
12
|
+
npx @evermore.work/create-evermore-plugin @acme/my-plugin \
|
|
13
|
+
--template connector \
|
|
14
|
+
--category connector \
|
|
15
|
+
--display-name "Acme Connector" \
|
|
16
|
+
--description "Syncs Acme data into Evermore" \
|
|
17
|
+
--author "Acme Inc"
|
|
18
|
+
```
|
|
19
|
+
|
|
20
|
+
Supported templates: `default`, `connector`, `workspace`
|
|
21
|
+
Supported categories: `connector`, `workspace`, `automation`, `ui`
|
|
22
|
+
|
|
23
|
+
Generates:
|
|
24
|
+
- typed manifest + worker entrypoint
|
|
25
|
+
- example UI widget using the supported `@evermore.work/plugin-sdk/ui` hooks
|
|
26
|
+
- test file using `@evermore.work/plugin-sdk/testing`
|
|
27
|
+
- `esbuild` and `rollup` config files using SDK bundler presets
|
|
28
|
+
- dev server script for hot-reload (`evermore-plugin-dev-server`)
|
|
29
|
+
|
|
30
|
+
The scaffold starts with plain React elements so the generated plugin stays minimal. For Evermore-native controls, import shared host components such as `MarkdownEditor`, `FileTree`, `AssigneePicker`, and `ProjectPicker` from `@evermore.work/plugin-sdk/ui`.
|
|
31
|
+
|
|
32
|
+
Inside this repo, the generated package uses `@evermore.work/plugin-sdk` via `workspace:*`.
|
|
33
|
+
|
|
34
|
+
Outside this repo, the scaffold snapshots `@evermore.work/plugin-sdk` from your local Evermore checkout into a `.evermore-sdk/` tarball and points the generated package at that local file by default. You can override the SDK source explicitly:
|
|
35
|
+
|
|
36
|
+
```bash
|
|
37
|
+
node packages/plugins/create-evermore-plugin/dist/index.js @acme/my-plugin \
|
|
38
|
+
--output /absolute/path/to/plugins \
|
|
39
|
+
--sdk-path /absolute/path/to/evermore/packages/plugins/sdk
|
|
40
|
+
```
|
|
41
|
+
|
|
42
|
+
That gives you an outside-repo local development path before the SDK is published to npm.
|
|
43
|
+
|
|
44
|
+
## Workflow after scaffolding
|
|
45
|
+
|
|
46
|
+
```bash
|
|
47
|
+
cd my-plugin
|
|
48
|
+
pnpm install
|
|
49
|
+
pnpm dev # watch worker + manifest + ui bundles
|
|
50
|
+
pnpm dev:ui # local UI preview server with hot-reload events
|
|
51
|
+
pnpm test
|
|
52
|
+
```
|
package/dist/index.d.ts
ADDED
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
declare const VALID_TEMPLATES: readonly ["default", "connector", "workspace", "environment"];
|
|
3
|
+
type PluginTemplate = (typeof VALID_TEMPLATES)[number];
|
|
4
|
+
export interface ScaffoldPluginOptions {
|
|
5
|
+
pluginName: string;
|
|
6
|
+
outputDir: string;
|
|
7
|
+
template?: PluginTemplate;
|
|
8
|
+
displayName?: string;
|
|
9
|
+
description?: string;
|
|
10
|
+
author?: string;
|
|
11
|
+
category?: "connector" | "workspace" | "automation" | "ui" | "environment";
|
|
12
|
+
sdkPath?: string;
|
|
13
|
+
}
|
|
14
|
+
/** Validate npm-style plugin package names (scoped or unscoped). */
|
|
15
|
+
export declare function isValidPluginName(name: string): boolean;
|
|
16
|
+
/**
|
|
17
|
+
* Generate a complete Evermore plugin starter project.
|
|
18
|
+
*
|
|
19
|
+
* Output includes manifest/worker/UI entries, SDK harness tests, bundler presets,
|
|
20
|
+
* and a local dev server script for hot-reload workflow.
|
|
21
|
+
*/
|
|
22
|
+
export declare function scaffoldPluginProject(options: ScaffoldPluginOptions): string;
|
|
23
|
+
export {};
|
|
24
|
+
//# sourceMappingURL=index.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":";AAMA,QAAA,MAAM,eAAe,+DAAgE,CAAC;AACtF,KAAK,cAAc,GAAG,CAAC,OAAO,eAAe,CAAC,CAAC,MAAM,CAAC,CAAC;AAGvD,MAAM,WAAW,qBAAqB;IACpC,UAAU,EAAE,MAAM,CAAC;IACnB,SAAS,EAAE,MAAM,CAAC;IAClB,QAAQ,CAAC,EAAE,cAAc,CAAC;IAC1B,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,QAAQ,CAAC,EAAE,WAAW,GAAG,WAAW,GAAG,YAAY,GAAG,IAAI,GAAG,aAAa,CAAC;IAC3E,OAAO,CAAC,EAAE,MAAM,CAAC;CAClB;AAED,oEAAoE;AACpE,wBAAgB,iBAAiB,CAAC,IAAI,EAAE,MAAM,GAAG,OAAO,CAIvD;AAsFD;;;;;GAKG;AACH,wBAAgB,qBAAqB,CAAC,OAAO,EAAE,qBAAqB,GAAG,MAAM,CAkjB5E"}
|
package/dist/index.js
ADDED
|
@@ -0,0 +1,622 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
import { execFileSync } from "node:child_process";
|
|
3
|
+
import fs from "node:fs";
|
|
4
|
+
import path from "node:path";
|
|
5
|
+
import { fileURLToPath } from "node:url";
|
|
6
|
+
const VALID_TEMPLATES = ["default", "connector", "workspace", "environment"];
|
|
7
|
+
const VALID_CATEGORIES = new Set(["connector", "workspace", "automation", "ui", "environment"]);
|
|
8
|
+
/** Validate npm-style plugin package names (scoped or unscoped). */
|
|
9
|
+
export function isValidPluginName(name) {
|
|
10
|
+
const scopedPattern = /^@[a-z0-9_-]+\/[a-z0-9._-]+$/;
|
|
11
|
+
const unscopedPattern = /^[a-z0-9._-]+$/;
|
|
12
|
+
return scopedPattern.test(name) || unscopedPattern.test(name);
|
|
13
|
+
}
|
|
14
|
+
/** Convert `@scope/name` to an output directory basename (`name`). */
|
|
15
|
+
function packageToDirName(pluginName) {
|
|
16
|
+
return pluginName.replace(/^@[^/]+\//, "");
|
|
17
|
+
}
|
|
18
|
+
/** Convert an npm package name into a manifest-safe plugin id. */
|
|
19
|
+
function packageToManifestId(pluginName) {
|
|
20
|
+
if (!pluginName.startsWith("@")) {
|
|
21
|
+
return pluginName;
|
|
22
|
+
}
|
|
23
|
+
return pluginName.slice(1).replace("/", ".");
|
|
24
|
+
}
|
|
25
|
+
/** Build a human-readable display name from package name tokens. */
|
|
26
|
+
function makeDisplayName(pluginName) {
|
|
27
|
+
const raw = packageToDirName(pluginName).replace(/[._-]+/g, " ").trim();
|
|
28
|
+
return raw
|
|
29
|
+
.split(/\s+/)
|
|
30
|
+
.map((part) => part.charAt(0).toUpperCase() + part.slice(1))
|
|
31
|
+
.join(" ");
|
|
32
|
+
}
|
|
33
|
+
function writeFile(target, content) {
|
|
34
|
+
fs.mkdirSync(path.dirname(target), { recursive: true });
|
|
35
|
+
fs.writeFileSync(target, content);
|
|
36
|
+
}
|
|
37
|
+
function quote(value) {
|
|
38
|
+
return JSON.stringify(value);
|
|
39
|
+
}
|
|
40
|
+
function toPosixPath(value) {
|
|
41
|
+
return value.split(path.sep).join("/");
|
|
42
|
+
}
|
|
43
|
+
function formatFileDependency(absPath) {
|
|
44
|
+
return `file:${toPosixPath(path.resolve(absPath))}`;
|
|
45
|
+
}
|
|
46
|
+
function getLocalSdkPackagePath() {
|
|
47
|
+
return path.resolve(path.dirname(fileURLToPath(import.meta.url)), "..", "..", "sdk");
|
|
48
|
+
}
|
|
49
|
+
function getRepoRootFromSdkPath(sdkPath) {
|
|
50
|
+
return path.resolve(sdkPath, "..", "..", "..");
|
|
51
|
+
}
|
|
52
|
+
function getLocalSharedPackagePath(sdkPath) {
|
|
53
|
+
return path.resolve(getRepoRootFromSdkPath(sdkPath), "packages", "shared");
|
|
54
|
+
}
|
|
55
|
+
function isInsideDir(targetPath, parentPath) {
|
|
56
|
+
const relative = path.relative(parentPath, targetPath);
|
|
57
|
+
return relative === "" || (!relative.startsWith("..") && !path.isAbsolute(relative));
|
|
58
|
+
}
|
|
59
|
+
function packLocalPackage(packagePath, outputDir) {
|
|
60
|
+
const packageJsonPath = path.join(packagePath, "package.json");
|
|
61
|
+
if (!fs.existsSync(packageJsonPath)) {
|
|
62
|
+
throw new Error(`Package package.json not found at ${packageJsonPath}`);
|
|
63
|
+
}
|
|
64
|
+
const packageJson = JSON.parse(fs.readFileSync(packageJsonPath, "utf8"));
|
|
65
|
+
const packageName = packageJson.name ?? path.basename(packagePath);
|
|
66
|
+
const packageVersion = packageJson.version ?? "0.0.0";
|
|
67
|
+
const tarballFileName = `${packageName.replace(/^@/, "").replace("/", "-")}-${packageVersion}.tgz`;
|
|
68
|
+
const sdkBundleDir = path.join(outputDir, ".evermore-sdk");
|
|
69
|
+
fs.mkdirSync(sdkBundleDir, { recursive: true });
|
|
70
|
+
execFileSync("pnpm", ["build"], { cwd: packagePath, stdio: "pipe" });
|
|
71
|
+
execFileSync("pnpm", ["pack", "--pack-destination", sdkBundleDir], { cwd: packagePath, stdio: "pipe" });
|
|
72
|
+
const tarballPath = path.join(sdkBundleDir, tarballFileName);
|
|
73
|
+
if (!fs.existsSync(tarballPath)) {
|
|
74
|
+
throw new Error(`Packed tarball was not created at ${tarballPath}`);
|
|
75
|
+
}
|
|
76
|
+
return tarballPath;
|
|
77
|
+
}
|
|
78
|
+
/**
|
|
79
|
+
* Generate a complete Evermore plugin starter project.
|
|
80
|
+
*
|
|
81
|
+
* Output includes manifest/worker/UI entries, SDK harness tests, bundler presets,
|
|
82
|
+
* and a local dev server script for hot-reload workflow.
|
|
83
|
+
*/
|
|
84
|
+
export function scaffoldPluginProject(options) {
|
|
85
|
+
const template = options.template ?? "default";
|
|
86
|
+
if (!VALID_TEMPLATES.includes(template)) {
|
|
87
|
+
throw new Error(`Invalid template '${template}'. Expected one of: ${VALID_TEMPLATES.join(", ")}`);
|
|
88
|
+
}
|
|
89
|
+
if (!isValidPluginName(options.pluginName)) {
|
|
90
|
+
throw new Error("Invalid plugin name. Must be lowercase and may include scope, dots, underscores, or hyphens.");
|
|
91
|
+
}
|
|
92
|
+
if (options.category && !VALID_CATEGORIES.has(options.category)) {
|
|
93
|
+
throw new Error(`Invalid category '${options.category}'. Expected one of: ${[...VALID_CATEGORIES].join(", ")}`);
|
|
94
|
+
}
|
|
95
|
+
const outputDir = path.resolve(options.outputDir);
|
|
96
|
+
if (fs.existsSync(outputDir)) {
|
|
97
|
+
throw new Error(`Directory already exists: ${outputDir}`);
|
|
98
|
+
}
|
|
99
|
+
const displayName = options.displayName ?? makeDisplayName(options.pluginName);
|
|
100
|
+
const description = options.description ?? "A Evermore plugin";
|
|
101
|
+
const author = options.author ?? "Plugin Author";
|
|
102
|
+
const category = options.category ?? (template === "workspace" ? "workspace" : template === "environment" ? "environment" : "connector");
|
|
103
|
+
const manifestId = packageToManifestId(options.pluginName);
|
|
104
|
+
const localSdkPath = path.resolve(options.sdkPath ?? getLocalSdkPackagePath());
|
|
105
|
+
const localSharedPath = getLocalSharedPackagePath(localSdkPath);
|
|
106
|
+
const repoRoot = getRepoRootFromSdkPath(localSdkPath);
|
|
107
|
+
const useWorkspaceSdk = isInsideDir(outputDir, repoRoot);
|
|
108
|
+
fs.mkdirSync(outputDir, { recursive: true });
|
|
109
|
+
const packedSharedTarball = useWorkspaceSdk ? null : packLocalPackage(localSharedPath, outputDir);
|
|
110
|
+
const sdkDependency = useWorkspaceSdk
|
|
111
|
+
? "workspace:*"
|
|
112
|
+
: `file:${toPosixPath(path.relative(outputDir, packLocalPackage(localSdkPath, outputDir)))}`;
|
|
113
|
+
const packageJson = {
|
|
114
|
+
name: options.pluginName,
|
|
115
|
+
version: "0.1.0",
|
|
116
|
+
type: "module",
|
|
117
|
+
private: true,
|
|
118
|
+
description,
|
|
119
|
+
scripts: {
|
|
120
|
+
build: "node ./esbuild.config.mjs",
|
|
121
|
+
"build:rollup": "rollup -c",
|
|
122
|
+
dev: "node ./esbuild.config.mjs --watch",
|
|
123
|
+
"dev:ui": "evermore-plugin-dev-server --root . --ui-dir dist/ui --port 4177",
|
|
124
|
+
test: "vitest run --config ./vitest.config.ts",
|
|
125
|
+
typecheck: "tsc --noEmit"
|
|
126
|
+
},
|
|
127
|
+
evermorePlugin: {
|
|
128
|
+
manifest: "./dist/manifest.js",
|
|
129
|
+
worker: "./dist/worker.js",
|
|
130
|
+
ui: "./dist/ui/"
|
|
131
|
+
},
|
|
132
|
+
keywords: ["evermore", "plugin", category],
|
|
133
|
+
author,
|
|
134
|
+
license: "MIT",
|
|
135
|
+
...(packedSharedTarball
|
|
136
|
+
? {
|
|
137
|
+
pnpm: {
|
|
138
|
+
overrides: {
|
|
139
|
+
"@evermore.work/shared": `file:${toPosixPath(path.relative(outputDir, packedSharedTarball))}`,
|
|
140
|
+
},
|
|
141
|
+
},
|
|
142
|
+
}
|
|
143
|
+
: {}),
|
|
144
|
+
devDependencies: {
|
|
145
|
+
...(packedSharedTarball
|
|
146
|
+
? {
|
|
147
|
+
"@evermore.work/shared": `file:${toPosixPath(path.relative(outputDir, packedSharedTarball))}`,
|
|
148
|
+
}
|
|
149
|
+
: {}),
|
|
150
|
+
"@evermore.work/plugin-sdk": sdkDependency,
|
|
151
|
+
"@rollup/plugin-node-resolve": "^16.0.1",
|
|
152
|
+
"@rollup/plugin-typescript": "^12.1.2",
|
|
153
|
+
"@types/node": "^24.6.0",
|
|
154
|
+
"@types/react": "^19.0.8",
|
|
155
|
+
esbuild: "^0.27.3",
|
|
156
|
+
rollup: "^4.38.0",
|
|
157
|
+
tslib: "^2.8.1",
|
|
158
|
+
typescript: "^5.7.3",
|
|
159
|
+
vitest: "^3.0.5"
|
|
160
|
+
},
|
|
161
|
+
peerDependencies: {
|
|
162
|
+
react: ">=18"
|
|
163
|
+
}
|
|
164
|
+
};
|
|
165
|
+
writeFile(path.join(outputDir, "package.json"), `${JSON.stringify(packageJson, null, 2)}\n`);
|
|
166
|
+
const tsconfig = {
|
|
167
|
+
compilerOptions: {
|
|
168
|
+
target: "ES2022",
|
|
169
|
+
module: "NodeNext",
|
|
170
|
+
moduleResolution: "NodeNext",
|
|
171
|
+
lib: ["ES2022", "DOM"],
|
|
172
|
+
jsx: "react-jsx",
|
|
173
|
+
strict: true,
|
|
174
|
+
skipLibCheck: true,
|
|
175
|
+
declaration: true,
|
|
176
|
+
declarationMap: true,
|
|
177
|
+
sourceMap: true,
|
|
178
|
+
outDir: "dist",
|
|
179
|
+
rootDir: "."
|
|
180
|
+
},
|
|
181
|
+
include: ["src", "tests"],
|
|
182
|
+
exclude: ["dist", "node_modules"]
|
|
183
|
+
};
|
|
184
|
+
writeFile(path.join(outputDir, "tsconfig.json"), `${JSON.stringify(tsconfig, null, 2)}\n`);
|
|
185
|
+
writeFile(path.join(outputDir, "esbuild.config.mjs"), `import esbuild from "esbuild";
|
|
186
|
+
import { createPluginBundlerPresets } from "@evermore.work/plugin-sdk/bundlers";
|
|
187
|
+
|
|
188
|
+
const presets = createPluginBundlerPresets({ uiEntry: "src/ui/index.tsx" });
|
|
189
|
+
const watch = process.argv.includes("--watch");
|
|
190
|
+
|
|
191
|
+
const workerCtx = await esbuild.context(presets.esbuild.worker);
|
|
192
|
+
const manifestCtx = await esbuild.context(presets.esbuild.manifest);
|
|
193
|
+
const uiCtx = await esbuild.context(presets.esbuild.ui);
|
|
194
|
+
|
|
195
|
+
if (watch) {
|
|
196
|
+
await Promise.all([workerCtx.watch(), manifestCtx.watch(), uiCtx.watch()]);
|
|
197
|
+
console.log("esbuild watch mode enabled for worker, manifest, and ui");
|
|
198
|
+
} else {
|
|
199
|
+
await Promise.all([workerCtx.rebuild(), manifestCtx.rebuild(), uiCtx.rebuild()]);
|
|
200
|
+
await Promise.all([workerCtx.dispose(), manifestCtx.dispose(), uiCtx.dispose()]);
|
|
201
|
+
}
|
|
202
|
+
`);
|
|
203
|
+
writeFile(path.join(outputDir, "rollup.config.mjs"), `import { nodeResolve } from "@rollup/plugin-node-resolve";
|
|
204
|
+
import typescript from "@rollup/plugin-typescript";
|
|
205
|
+
import { createPluginBundlerPresets } from "@evermore.work/plugin-sdk/bundlers";
|
|
206
|
+
|
|
207
|
+
const presets = createPluginBundlerPresets({ uiEntry: "src/ui/index.tsx" });
|
|
208
|
+
|
|
209
|
+
function withPlugins(config) {
|
|
210
|
+
if (!config) return null;
|
|
211
|
+
return {
|
|
212
|
+
...config,
|
|
213
|
+
plugins: [
|
|
214
|
+
nodeResolve({
|
|
215
|
+
extensions: [".ts", ".tsx", ".js", ".jsx", ".mjs"],
|
|
216
|
+
}),
|
|
217
|
+
typescript({
|
|
218
|
+
tsconfig: "./tsconfig.json",
|
|
219
|
+
declaration: false,
|
|
220
|
+
declarationMap: false,
|
|
221
|
+
}),
|
|
222
|
+
],
|
|
223
|
+
};
|
|
224
|
+
}
|
|
225
|
+
|
|
226
|
+
export default [
|
|
227
|
+
withPlugins(presets.rollup.manifest),
|
|
228
|
+
withPlugins(presets.rollup.worker),
|
|
229
|
+
withPlugins(presets.rollup.ui),
|
|
230
|
+
].filter(Boolean);
|
|
231
|
+
`);
|
|
232
|
+
writeFile(path.join(outputDir, "vitest.config.ts"), `import { defineConfig } from "vitest/config";
|
|
233
|
+
|
|
234
|
+
export default defineConfig({
|
|
235
|
+
test: {
|
|
236
|
+
include: ["tests/**/*.spec.ts"],
|
|
237
|
+
environment: "node",
|
|
238
|
+
},
|
|
239
|
+
});
|
|
240
|
+
`);
|
|
241
|
+
if (template === "environment") {
|
|
242
|
+
writeFile(path.join(outputDir, "src", "manifest.ts"), `import type { EvermorePluginManifestV1 } from "@evermore.work/plugin-sdk";
|
|
243
|
+
|
|
244
|
+
const manifest: EvermorePluginManifestV1 = {
|
|
245
|
+
id: ${quote(manifestId)},
|
|
246
|
+
apiVersion: 1,
|
|
247
|
+
version: "0.1.0",
|
|
248
|
+
displayName: ${quote(displayName)},
|
|
249
|
+
description: ${quote(description)},
|
|
250
|
+
author: ${quote(author)},
|
|
251
|
+
categories: [${quote(category)}],
|
|
252
|
+
capabilities: [
|
|
253
|
+
"environment.drivers.register",
|
|
254
|
+
"plugin.state.read",
|
|
255
|
+
"plugin.state.write"
|
|
256
|
+
],
|
|
257
|
+
entrypoints: {
|
|
258
|
+
worker: "./dist/worker.js",
|
|
259
|
+
ui: "./dist/ui"
|
|
260
|
+
},
|
|
261
|
+
environmentDrivers: [
|
|
262
|
+
{
|
|
263
|
+
driverKey: ${quote(manifestId + "-driver")},
|
|
264
|
+
displayName: ${quote(displayName + " Driver")}
|
|
265
|
+
}
|
|
266
|
+
],
|
|
267
|
+
ui: {
|
|
268
|
+
slots: [
|
|
269
|
+
{
|
|
270
|
+
type: "dashboardWidget",
|
|
271
|
+
id: "health-widget",
|
|
272
|
+
displayName: ${quote(`${displayName} Health`)},
|
|
273
|
+
exportName: "DashboardWidget"
|
|
274
|
+
}
|
|
275
|
+
]
|
|
276
|
+
}
|
|
277
|
+
};
|
|
278
|
+
|
|
279
|
+
export default manifest;
|
|
280
|
+
`);
|
|
281
|
+
writeFile(path.join(outputDir, "src", "worker.ts"), `import { definePlugin, runWorker } from "@evermore.work/plugin-sdk";
|
|
282
|
+
import type {
|
|
283
|
+
PluginEnvironmentValidateConfigParams,
|
|
284
|
+
PluginEnvironmentProbeParams,
|
|
285
|
+
PluginEnvironmentAcquireLeaseParams,
|
|
286
|
+
PluginEnvironmentResumeLeaseParams,
|
|
287
|
+
PluginEnvironmentReleaseLeaseParams,
|
|
288
|
+
PluginEnvironmentDestroyLeaseParams,
|
|
289
|
+
PluginEnvironmentRealizeWorkspaceParams,
|
|
290
|
+
PluginEnvironmentExecuteParams,
|
|
291
|
+
} from "@evermore.work/plugin-sdk";
|
|
292
|
+
|
|
293
|
+
const plugin = definePlugin({
|
|
294
|
+
async setup(ctx) {
|
|
295
|
+
ctx.data.register("health", async () => {
|
|
296
|
+
return { status: "ok", checkedAt: new Date().toISOString() };
|
|
297
|
+
});
|
|
298
|
+
},
|
|
299
|
+
|
|
300
|
+
async onHealth() {
|
|
301
|
+
return { status: "ok", message: "Environment plugin worker is running" };
|
|
302
|
+
},
|
|
303
|
+
|
|
304
|
+
async onEnvironmentValidateConfig(params: PluginEnvironmentValidateConfigParams) {
|
|
305
|
+
if (!params.config || typeof params.config !== "object") {
|
|
306
|
+
return { ok: false, errors: ["Config must be a non-null object"] };
|
|
307
|
+
}
|
|
308
|
+
return { ok: true, normalizedConfig: params.config };
|
|
309
|
+
},
|
|
310
|
+
|
|
311
|
+
async onEnvironmentProbe(_params: PluginEnvironmentProbeParams) {
|
|
312
|
+
return { ok: true, summary: "Environment is reachable" };
|
|
313
|
+
},
|
|
314
|
+
|
|
315
|
+
async onEnvironmentAcquireLease(params: PluginEnvironmentAcquireLeaseParams) {
|
|
316
|
+
const providerLeaseId = \`lease-\${params.runId}-\${Date.now()}\`;
|
|
317
|
+
return {
|
|
318
|
+
providerLeaseId,
|
|
319
|
+
metadata: { acquiredAt: new Date().toISOString() },
|
|
320
|
+
};
|
|
321
|
+
},
|
|
322
|
+
|
|
323
|
+
async onEnvironmentResumeLease(params: PluginEnvironmentResumeLeaseParams) {
|
|
324
|
+
return {
|
|
325
|
+
providerLeaseId: params.providerLeaseId,
|
|
326
|
+
metadata: { ...params.leaseMetadata, resumed: true },
|
|
327
|
+
};
|
|
328
|
+
},
|
|
329
|
+
|
|
330
|
+
async onEnvironmentReleaseLease(_params: PluginEnvironmentReleaseLeaseParams) {
|
|
331
|
+
// Release provider-side resources here
|
|
332
|
+
},
|
|
333
|
+
|
|
334
|
+
async onEnvironmentDestroyLease(_params: PluginEnvironmentDestroyLeaseParams) {
|
|
335
|
+
// Destroy provider-side resources here
|
|
336
|
+
},
|
|
337
|
+
|
|
338
|
+
async onEnvironmentRealizeWorkspace(params: PluginEnvironmentRealizeWorkspaceParams) {
|
|
339
|
+
const cwd = params.workspace.remotePath ?? params.workspace.localPath ?? "/tmp/workspace";
|
|
340
|
+
return { cwd, metadata: { realized: true } };
|
|
341
|
+
},
|
|
342
|
+
|
|
343
|
+
async onEnvironmentExecute(params: PluginEnvironmentExecuteParams) {
|
|
344
|
+
// Replace this with real command execution against your provider
|
|
345
|
+
return {
|
|
346
|
+
exitCode: 0,
|
|
347
|
+
timedOut: false,
|
|
348
|
+
stdout: \`Executed: \${params.command}\`,
|
|
349
|
+
stderr: "",
|
|
350
|
+
};
|
|
351
|
+
},
|
|
352
|
+
});
|
|
353
|
+
|
|
354
|
+
export default plugin;
|
|
355
|
+
runWorker(plugin, import.meta.url);
|
|
356
|
+
`);
|
|
357
|
+
writeFile(path.join(outputDir, "src", "ui", "index.tsx"), `import { usePluginData, type PluginWidgetProps } from "@evermore.work/plugin-sdk/ui";
|
|
358
|
+
|
|
359
|
+
type HealthData = {
|
|
360
|
+
status: "ok" | "degraded" | "error";
|
|
361
|
+
checkedAt: string;
|
|
362
|
+
};
|
|
363
|
+
|
|
364
|
+
export function DashboardWidget(_props: PluginWidgetProps) {
|
|
365
|
+
const { data, loading, error } = usePluginData<HealthData>("health");
|
|
366
|
+
|
|
367
|
+
if (loading) return <div>Loading environment health...</div>;
|
|
368
|
+
if (error) return <div>Plugin error: {error.message}</div>;
|
|
369
|
+
|
|
370
|
+
return (
|
|
371
|
+
<div style={{ display: "grid", gap: "0.5rem" }}>
|
|
372
|
+
<strong>${displayName}</strong>
|
|
373
|
+
<div>Health: {data?.status ?? "unknown"}</div>
|
|
374
|
+
<div>Checked: {data?.checkedAt ?? "never"}</div>
|
|
375
|
+
</div>
|
|
376
|
+
);
|
|
377
|
+
}
|
|
378
|
+
`);
|
|
379
|
+
writeFile(path.join(outputDir, "tests", "plugin.spec.ts"), `import { describe, expect, it } from "vitest";
|
|
380
|
+
import {
|
|
381
|
+
createEnvironmentTestHarness,
|
|
382
|
+
createFakeEnvironmentDriver,
|
|
383
|
+
assertEnvironmentEventOrder,
|
|
384
|
+
assertLeaseLifecycle,
|
|
385
|
+
} from "@evermore.work/plugin-sdk/testing";
|
|
386
|
+
import manifest from "../src/manifest.js";
|
|
387
|
+
import plugin from "../src/worker.js";
|
|
388
|
+
|
|
389
|
+
const ENV_ID = "env-test-1";
|
|
390
|
+
const BASE_PARAMS = {
|
|
391
|
+
driverKey: manifest.environmentDrivers![0].driverKey,
|
|
392
|
+
companyId: "co-1",
|
|
393
|
+
environmentId: ENV_ID,
|
|
394
|
+
config: {},
|
|
395
|
+
};
|
|
396
|
+
|
|
397
|
+
describe("environment plugin scaffold", () => {
|
|
398
|
+
it("validates config", async () => {
|
|
399
|
+
const driver = createFakeEnvironmentDriver({ driverKey: BASE_PARAMS.driverKey });
|
|
400
|
+
const harness = createEnvironmentTestHarness({ manifest, environmentDriver: driver });
|
|
401
|
+
await plugin.definition.setup(harness.ctx);
|
|
402
|
+
|
|
403
|
+
const result = await plugin.definition.onEnvironmentValidateConfig!({
|
|
404
|
+
driverKey: BASE_PARAMS.driverKey,
|
|
405
|
+
config: { host: "test" },
|
|
406
|
+
});
|
|
407
|
+
expect(result.ok).toBe(true);
|
|
408
|
+
});
|
|
409
|
+
|
|
410
|
+
it("probes the environment", async () => {
|
|
411
|
+
const driver = createFakeEnvironmentDriver({ driverKey: BASE_PARAMS.driverKey });
|
|
412
|
+
const harness = createEnvironmentTestHarness({ manifest, environmentDriver: driver });
|
|
413
|
+
await plugin.definition.setup(harness.ctx);
|
|
414
|
+
|
|
415
|
+
const result = await plugin.definition.onEnvironmentProbe!(BASE_PARAMS);
|
|
416
|
+
expect(result.ok).toBe(true);
|
|
417
|
+
});
|
|
418
|
+
|
|
419
|
+
it("runs a full lease lifecycle through the harness", async () => {
|
|
420
|
+
const driver = createFakeEnvironmentDriver({ driverKey: BASE_PARAMS.driverKey });
|
|
421
|
+
const harness = createEnvironmentTestHarness({ manifest, environmentDriver: driver });
|
|
422
|
+
await plugin.definition.setup(harness.ctx);
|
|
423
|
+
|
|
424
|
+
const lease = await harness.acquireLease({ ...BASE_PARAMS, runId: "run-1" });
|
|
425
|
+
expect(lease.providerLeaseId).toBeTruthy();
|
|
426
|
+
|
|
427
|
+
await harness.realizeWorkspace({
|
|
428
|
+
...BASE_PARAMS,
|
|
429
|
+
lease,
|
|
430
|
+
workspace: { localPath: "/tmp/test" },
|
|
431
|
+
});
|
|
432
|
+
|
|
433
|
+
await harness.releaseLease({
|
|
434
|
+
...BASE_PARAMS,
|
|
435
|
+
providerLeaseId: lease.providerLeaseId,
|
|
436
|
+
});
|
|
437
|
+
|
|
438
|
+
assertEnvironmentEventOrder(harness.environmentEvents, [
|
|
439
|
+
"acquireLease",
|
|
440
|
+
"realizeWorkspace",
|
|
441
|
+
"releaseLease",
|
|
442
|
+
]);
|
|
443
|
+
assertLeaseLifecycle(harness.environmentEvents, ENV_ID);
|
|
444
|
+
});
|
|
445
|
+
});
|
|
446
|
+
`);
|
|
447
|
+
}
|
|
448
|
+
else {
|
|
449
|
+
writeFile(path.join(outputDir, "src", "manifest.ts"), `import type { EvermorePluginManifestV1 } from "@evermore.work/plugin-sdk";
|
|
450
|
+
|
|
451
|
+
const manifest: EvermorePluginManifestV1 = {
|
|
452
|
+
id: ${quote(manifestId)},
|
|
453
|
+
apiVersion: 1,
|
|
454
|
+
version: "0.1.0",
|
|
455
|
+
displayName: ${quote(displayName)},
|
|
456
|
+
description: ${quote(description)},
|
|
457
|
+
author: ${quote(author)},
|
|
458
|
+
categories: [${quote(category)}],
|
|
459
|
+
capabilities: [
|
|
460
|
+
"events.subscribe",
|
|
461
|
+
"plugin.state.read",
|
|
462
|
+
"plugin.state.write"
|
|
463
|
+
],
|
|
464
|
+
entrypoints: {
|
|
465
|
+
worker: "./dist/worker.js",
|
|
466
|
+
ui: "./dist/ui"
|
|
467
|
+
},
|
|
468
|
+
ui: {
|
|
469
|
+
slots: [
|
|
470
|
+
{
|
|
471
|
+
type: "dashboardWidget",
|
|
472
|
+
id: "health-widget",
|
|
473
|
+
displayName: ${quote(`${displayName} Health`)},
|
|
474
|
+
exportName: "DashboardWidget"
|
|
475
|
+
}
|
|
476
|
+
]
|
|
477
|
+
}
|
|
478
|
+
};
|
|
479
|
+
|
|
480
|
+
export default manifest;
|
|
481
|
+
`);
|
|
482
|
+
writeFile(path.join(outputDir, "src", "worker.ts"), `import { definePlugin, runWorker } from "@evermore.work/plugin-sdk";
|
|
483
|
+
|
|
484
|
+
const plugin = definePlugin({
|
|
485
|
+
async setup(ctx) {
|
|
486
|
+
ctx.events.on("issue.created", async (event) => {
|
|
487
|
+
const issueId = event.entityId ?? "unknown";
|
|
488
|
+
await ctx.state.set({ scopeKind: "issue", scopeId: issueId, stateKey: "seen" }, true);
|
|
489
|
+
ctx.logger.info("Observed issue.created", { issueId });
|
|
490
|
+
});
|
|
491
|
+
|
|
492
|
+
ctx.data.register("health", async () => {
|
|
493
|
+
return { status: "ok", checkedAt: new Date().toISOString() };
|
|
494
|
+
});
|
|
495
|
+
|
|
496
|
+
ctx.actions.register("ping", async () => {
|
|
497
|
+
ctx.logger.info("Ping action invoked");
|
|
498
|
+
return { pong: true, at: new Date().toISOString() };
|
|
499
|
+
});
|
|
500
|
+
},
|
|
501
|
+
|
|
502
|
+
async onHealth() {
|
|
503
|
+
return { status: "ok", message: "Plugin worker is running" };
|
|
504
|
+
}
|
|
505
|
+
});
|
|
506
|
+
|
|
507
|
+
export default plugin;
|
|
508
|
+
runWorker(plugin, import.meta.url);
|
|
509
|
+
`);
|
|
510
|
+
writeFile(path.join(outputDir, "src", "ui", "index.tsx"), `import { usePluginAction, usePluginData, type PluginWidgetProps } from "@evermore.work/plugin-sdk/ui";
|
|
511
|
+
|
|
512
|
+
type HealthData = {
|
|
513
|
+
status: "ok" | "degraded" | "error";
|
|
514
|
+
checkedAt: string;
|
|
515
|
+
};
|
|
516
|
+
|
|
517
|
+
export function DashboardWidget(_props: PluginWidgetProps) {
|
|
518
|
+
const { data, loading, error } = usePluginData<HealthData>("health");
|
|
519
|
+
const ping = usePluginAction("ping");
|
|
520
|
+
|
|
521
|
+
if (loading) return <div>Loading plugin health...</div>;
|
|
522
|
+
if (error) return <div>Plugin error: {error.message}</div>;
|
|
523
|
+
|
|
524
|
+
return (
|
|
525
|
+
<div style={{ display: "grid", gap: "0.5rem" }}>
|
|
526
|
+
<strong>${displayName}</strong>
|
|
527
|
+
<div>Health: {data?.status ?? "unknown"}</div>
|
|
528
|
+
<div>Checked: {data?.checkedAt ?? "never"}</div>
|
|
529
|
+
<button onClick={() => void ping()}>Ping Worker</button>
|
|
530
|
+
</div>
|
|
531
|
+
);
|
|
532
|
+
}
|
|
533
|
+
`);
|
|
534
|
+
writeFile(path.join(outputDir, "tests", "plugin.spec.ts"), `import { describe, expect, it } from "vitest";
|
|
535
|
+
import { createTestHarness } from "@evermore.work/plugin-sdk/testing";
|
|
536
|
+
import manifest from "../src/manifest.js";
|
|
537
|
+
import plugin from "../src/worker.js";
|
|
538
|
+
|
|
539
|
+
describe("plugin scaffold", () => {
|
|
540
|
+
it("registers data + actions and handles events", async () => {
|
|
541
|
+
const harness = createTestHarness({ manifest, capabilities: [...manifest.capabilities, "events.emit"] });
|
|
542
|
+
await plugin.definition.setup(harness.ctx);
|
|
543
|
+
|
|
544
|
+
await harness.emit("issue.created", { issueId: "iss_1" }, { entityId: "iss_1", entityType: "issue" });
|
|
545
|
+
expect(harness.getState({ scopeKind: "issue", scopeId: "iss_1", stateKey: "seen" })).toBe(true);
|
|
546
|
+
|
|
547
|
+
const data = await harness.getData<{ status: string }>("health");
|
|
548
|
+
expect(data.status).toBe("ok");
|
|
549
|
+
|
|
550
|
+
const action = await harness.performAction<{ pong: boolean }>("ping");
|
|
551
|
+
expect(action.pong).toBe(true);
|
|
552
|
+
});
|
|
553
|
+
});
|
|
554
|
+
`);
|
|
555
|
+
}
|
|
556
|
+
writeFile(path.join(outputDir, "README.md"), `# ${displayName}
|
|
557
|
+
|
|
558
|
+
${description}
|
|
559
|
+
|
|
560
|
+
## Development
|
|
561
|
+
|
|
562
|
+
\`\`\`bash
|
|
563
|
+
pnpm install
|
|
564
|
+
pnpm dev # watch builds
|
|
565
|
+
pnpm dev:ui # local dev server with hot-reload events
|
|
566
|
+
pnpm test
|
|
567
|
+
\`\`\`
|
|
568
|
+
|
|
569
|
+
${sdkDependency.startsWith("file:")
|
|
570
|
+
? `This scaffold snapshots \`@evermore.work/plugin-sdk\` and \`@evermore.work/shared\` from a local Evermore checkout at:\n\n\`${toPosixPath(localSdkPath)}\`\n\nThe packed tarballs live in \`.evermore-sdk/\` for local development. Before publishing this plugin, switch those dependencies to published package versions once they are available on npm.\n\n`
|
|
571
|
+
: ""}
|
|
572
|
+
|
|
573
|
+
## Install Into Evermore
|
|
574
|
+
|
|
575
|
+
\`\`\`bash
|
|
576
|
+
curl -X POST http://127.0.0.1:3100/api/plugins/install \\
|
|
577
|
+
-H "Content-Type: application/json" \\
|
|
578
|
+
-d '{"packageName":"${toPosixPath(outputDir)}","isLocalPath":true}'
|
|
579
|
+
\`\`\`
|
|
580
|
+
|
|
581
|
+
## Build Options
|
|
582
|
+
|
|
583
|
+
- \`pnpm build\` uses esbuild presets from \`@evermore.work/plugin-sdk/bundlers\`.
|
|
584
|
+
- \`pnpm build:rollup\` uses rollup presets from the same SDK.
|
|
585
|
+
`);
|
|
586
|
+
writeFile(path.join(outputDir, ".gitignore"), "dist\nnode_modules\n.evermore-sdk\n");
|
|
587
|
+
return outputDir;
|
|
588
|
+
}
|
|
589
|
+
function parseArg(name) {
|
|
590
|
+
const index = process.argv.indexOf(name);
|
|
591
|
+
if (index === -1)
|
|
592
|
+
return undefined;
|
|
593
|
+
return process.argv[index + 1];
|
|
594
|
+
}
|
|
595
|
+
/** CLI wrapper for `scaffoldPluginProject`. */
|
|
596
|
+
function runCli() {
|
|
597
|
+
const pluginName = process.argv[2];
|
|
598
|
+
if (!pluginName) {
|
|
599
|
+
// eslint-disable-next-line no-console
|
|
600
|
+
console.error("Usage: create-evermore-plugin <name> [--template default|connector|workspace] [--output <dir>] [--sdk-path <evermore-sdk-path>]");
|
|
601
|
+
process.exit(1);
|
|
602
|
+
}
|
|
603
|
+
const template = (parseArg("--template") ?? "default");
|
|
604
|
+
const outputRoot = parseArg("--output") ?? process.cwd();
|
|
605
|
+
const targetDir = path.resolve(outputRoot, packageToDirName(pluginName));
|
|
606
|
+
const out = scaffoldPluginProject({
|
|
607
|
+
pluginName,
|
|
608
|
+
outputDir: targetDir,
|
|
609
|
+
template,
|
|
610
|
+
displayName: parseArg("--display-name"),
|
|
611
|
+
description: parseArg("--description"),
|
|
612
|
+
author: parseArg("--author"),
|
|
613
|
+
category: parseArg("--category"),
|
|
614
|
+
sdkPath: parseArg("--sdk-path"),
|
|
615
|
+
});
|
|
616
|
+
// eslint-disable-next-line no-console
|
|
617
|
+
console.log(`Created plugin scaffold at ${out}`);
|
|
618
|
+
}
|
|
619
|
+
if (import.meta.url === `file://${process.argv[1]}`) {
|
|
620
|
+
runCli();
|
|
621
|
+
}
|
|
622
|
+
//# sourceMappingURL=index.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"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"}
|
package/package.json
ADDED
|
@@ -0,0 +1,43 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "@evermore.work/create-evermore-plugin",
|
|
3
|
+
"version": "2026.509.0-canary.0",
|
|
4
|
+
"homepage": "https://github.com/phuctm97/evermore",
|
|
5
|
+
"bugs": {
|
|
6
|
+
"url": "https://github.com/phuctm97/evermore/issues"
|
|
7
|
+
},
|
|
8
|
+
"repository": {
|
|
9
|
+
"type": "git",
|
|
10
|
+
"url": "https://github.com/phuctm97/evermore",
|
|
11
|
+
"directory": "packages/plugins/create-evermore-plugin"
|
|
12
|
+
},
|
|
13
|
+
"type": "module",
|
|
14
|
+
"bin": {
|
|
15
|
+
"create-evermore-plugin": "./dist/index.js"
|
|
16
|
+
},
|
|
17
|
+
"exports": {
|
|
18
|
+
".": {
|
|
19
|
+
"types": "./dist/index.d.ts",
|
|
20
|
+
"import": "./dist/index.js"
|
|
21
|
+
}
|
|
22
|
+
},
|
|
23
|
+
"publishConfig": {
|
|
24
|
+
"access": "public"
|
|
25
|
+
},
|
|
26
|
+
"files": [
|
|
27
|
+
"dist"
|
|
28
|
+
],
|
|
29
|
+
"dependencies": {
|
|
30
|
+
"@evermore.work/plugin-sdk": "2026.509.0-canary.0"
|
|
31
|
+
},
|
|
32
|
+
"devDependencies": {
|
|
33
|
+
"@types/node": "^24.6.0",
|
|
34
|
+
"typescript": "^5.7.3"
|
|
35
|
+
},
|
|
36
|
+
"scripts": {
|
|
37
|
+
"build": "tsc",
|
|
38
|
+
"clean": "rm -rf dist",
|
|
39
|
+
"typecheck": "tsc --noEmit"
|
|
40
|
+
},
|
|
41
|
+
"main": "./dist/index.js",
|
|
42
|
+
"types": "./dist/index.d.ts"
|
|
43
|
+
}
|