@moinulmoin/eden 0.10.0 → 0.11.1
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 +3 -3
- package/dist/SKILL.md +215 -0
- package/dist/eve-control-plane.js +86 -3
- package/dist/index.js +19 -0
- package/package.json +4 -3
package/README.md
CHANGED
|
@@ -12,15 +12,15 @@ If you already have an Eve project, start with `eden deploy`.
|
|
|
12
12
|
Use any one of these package managers:
|
|
13
13
|
|
|
14
14
|
```sh
|
|
15
|
-
npm install --global @moinulmoin/eden@0.
|
|
15
|
+
npm install --global @moinulmoin/eden@0.11.1
|
|
16
16
|
```
|
|
17
17
|
|
|
18
18
|
```sh
|
|
19
|
-
pnpm add --global @moinulmoin/eden@0.
|
|
19
|
+
pnpm add --global @moinulmoin/eden@0.11.1
|
|
20
20
|
```
|
|
21
21
|
|
|
22
22
|
```sh
|
|
23
|
-
bun add --global @moinulmoin/eden@0.
|
|
23
|
+
bun add --global @moinulmoin/eden@0.11.1
|
|
24
24
|
```
|
|
25
25
|
|
|
26
26
|
Then confirm the CLI is available:
|
package/dist/SKILL.md
ADDED
|
@@ -0,0 +1,215 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: eden
|
|
3
|
+
description: Deploy, update, check, or remove a Vercel Eve agent on the user's own Cloudflare account with the Eden CLI. Use when someone wants to run an Eve project off Vercel, check whether an Eve project is ready for Cloudflare, ship a change to an Eden deployment, upgrade Eve on one, or tear one down.
|
|
4
|
+
---
|
|
5
|
+
|
|
6
|
+
# Eden: run an Eve agent on Cloudflare
|
|
7
|
+
|
|
8
|
+
Eden (`@moinulmoin/eden`) builds an existing Eve project as-is and runs it in a
|
|
9
|
+
Cloudflare Container behind a Worker on the user's own account. It never
|
|
10
|
+
rewrites the project; you make any needed changes yourself, guided by
|
|
11
|
+
preflight.
|
|
12
|
+
|
|
13
|
+
`npx @moinulmoin/eden skill` prints this guide for the installed CLI version.
|
|
14
|
+
Docs: https://github.com/moinulmoin/eden (failure and warning codes:
|
|
15
|
+
`docs/troubleshooting.md`).
|
|
16
|
+
|
|
17
|
+
## The loop
|
|
18
|
+
|
|
19
|
+
1. Check the machine and account (below).
|
|
20
|
+
2. Write the env file (below).
|
|
21
|
+
3. Run preflight and read the JSON:
|
|
22
|
+
|
|
23
|
+
```sh
|
|
24
|
+
npx @moinulmoin/eden preflight --env-file ~/.config/<agent>/preview.env --json
|
|
25
|
+
```
|
|
26
|
+
|
|
27
|
+
Preflight builds and boots the agent locally and checks Cloudflare access.
|
|
28
|
+
It changes nothing on Cloudflare. It prints one JSON object:
|
|
29
|
+
`ok`, `checks[]` (`id`, `status`, `message`, `remediation`) and
|
|
30
|
+
`warnings[]` (`id`, `message`, `remediation`).
|
|
31
|
+
4. Fix every failed check, then every warning, using its `remediation`. Re-run
|
|
32
|
+
until `ok` is `true` and no warning applies. A warning does not block a
|
|
33
|
+
deploy, but each one names something that breaks or loses data on
|
|
34
|
+
Cloudflare; only leave one if the user accepts that.
|
|
35
|
+
5. A clean preflight means the project can run on Cloudflare. It does not
|
|
36
|
+
check that keys are real: before deploying, make sure the user has replaced
|
|
37
|
+
every placeholder secret in the env file.
|
|
38
|
+
6. Deploy, then verify with a real message (below). Confirm with the user
|
|
39
|
+
first for production.
|
|
40
|
+
|
|
41
|
+
## Machine and account
|
|
42
|
+
|
|
43
|
+
- macOS or Linux, Node `>=24.17.0`
|
|
44
|
+
- Docker or OrbStack running, with linux/amd64 support
|
|
45
|
+
- Cloudflare Workers Paid plan (Containers need it), and Wrangler logged in:
|
|
46
|
+
`npx wrangler@4.147.0 login` (the user must do this in a browser)
|
|
47
|
+
|
|
48
|
+
## Project setup Cloudflare needs
|
|
49
|
+
|
|
50
|
+
These are what preflight checks most often. Fix them before the first run to
|
|
51
|
+
save a build.
|
|
52
|
+
|
|
53
|
+
- **One lockfile.** Either a root `package-lock.json`, or an exact
|
|
54
|
+
`"packageManager": "pnpm@x.y.z"` with a root `pnpm-lock.yaml`. Not both, not
|
|
55
|
+
Bun. Dependency install scripts do not run.
|
|
56
|
+
- **Sandbox.** Add `just-bash` as a production dependency. On Eve `0.83.0` and
|
|
57
|
+
later, also select it explicitly in `agent/sandbox.ts` (or
|
|
58
|
+
`agent/sandbox/sandbox.ts` if an `agent/sandbox/` folder exists):
|
|
59
|
+
|
|
60
|
+
```ts
|
|
61
|
+
import { defineSandbox } from 'eve/sandbox';
|
|
62
|
+
import { JustBashSandbox } from 'eve/sandbox/just-bash';
|
|
63
|
+
|
|
64
|
+
export const environment = JustBashSandbox.environment();
|
|
65
|
+
export default defineSandbox(() => environment.open());
|
|
66
|
+
```
|
|
67
|
+
|
|
68
|
+
Vercel Sandbox, Docker, and other providers do not run on Eden.
|
|
69
|
+
- **Channel auth (`EVE_AUTH_SCAFFOLD`).** The `eve init` auth in
|
|
70
|
+
`agent/channels/eve.ts` (`vercelOidc()`, `localDev()`, `placeholderAuth()`)
|
|
71
|
+
rejects every Cloudflare caller with 401. Replace it with a real
|
|
72
|
+
authenticator, for example a bearer token read from the env file. Keep
|
|
73
|
+
`localDev()` so `eve dev` still works locally; it is ignored in production:
|
|
74
|
+
|
|
75
|
+
```ts
|
|
76
|
+
import { localDev, type AuthFn } from "eve/channels/auth";
|
|
77
|
+
import { eveChannel } from "eve/channels/eve";
|
|
78
|
+
|
|
79
|
+
const authenticate: AuthFn<Request> = (request) => {
|
|
80
|
+
const expected = process.env.AGENT_AUTH_TOKEN;
|
|
81
|
+
if (!expected || request.headers.get("authorization") !== `Bearer ${expected}`) {
|
|
82
|
+
return null;
|
|
83
|
+
}
|
|
84
|
+
return {
|
|
85
|
+
attributes: {},
|
|
86
|
+
authenticator: "bearer-token",
|
|
87
|
+
principalId: "app-client",
|
|
88
|
+
principalType: "app",
|
|
89
|
+
};
|
|
90
|
+
};
|
|
91
|
+
|
|
92
|
+
export default eveChannel({ auth: [authenticate, localDev()] });
|
|
93
|
+
```
|
|
94
|
+
|
|
95
|
+
- **Model key (`EVE_AI_GATEWAY_KEY_MISSING`).** A string model such as
|
|
96
|
+
`"openai/gpt-5"` goes through Vercel AI Gateway. On Vercel that
|
|
97
|
+
authenticates automatically; on Cloudflare it needs `AI_GATEWAY_API_KEY` in
|
|
98
|
+
the env file. A direct provider such as `openai("…")` from `@ai-sdk/openai`
|
|
99
|
+
needs that provider's key instead.
|
|
100
|
+
- **Vercel Connect (`EVE_VERCEL_CONNECT`).** `connect()` from
|
|
101
|
+
`@vercel/connect/eve` gets credentials using an identity only Vercel
|
|
102
|
+
provides, so those connections fail on Cloudflare. Put the service's own key
|
|
103
|
+
or bot token in the env file and replace `connect(...)` in the connection
|
|
104
|
+
with `auth: { getToken: async () => ({ token: process.env.SERVICE_TOKEN! }) }`.
|
|
105
|
+
For per-user sign-in, use `defineInteractiveAuthorization` from
|
|
106
|
+
`eve/connections` with your own OAuth app. Having `@vercel/connect` in
|
|
107
|
+
`package.json` without importing it is fine.
|
|
108
|
+
- **Durable state (`EVE_WORLD_LOCAL`).** The default local Workflow World loses
|
|
109
|
+
sessions and pending approvals on every update. Use one of:
|
|
110
|
+
- `@moinulmoin/eden-world-cloudflare`: no database; sessions also survive Eve
|
|
111
|
+
upgrades. Add it as a production dependency and set in `agent/agent.ts`:
|
|
112
|
+
|
|
113
|
+
```ts
|
|
114
|
+
experimental: { workflow: { world: "@moinulmoin/eden-world-cloudflare" } },
|
|
115
|
+
```
|
|
116
|
+
|
|
117
|
+
- `@workflow/world-postgres` with a direct, unpooled Postgres URL in the env
|
|
118
|
+
file.
|
|
119
|
+
|
|
120
|
+
## Env file and secrets
|
|
121
|
+
|
|
122
|
+
- Lives **outside the project**, mode 600, for example
|
|
123
|
+
`~/.config/<agent>/preview.env`. Passed with `--env-file`.
|
|
124
|
+
- Exactly `KEY=value` per line: no quotes (they become part of the value), no
|
|
125
|
+
spaces around the name, `#` comment lines allowed.
|
|
126
|
+
- Holds the model key and every secret the agent reads (auth token, service
|
|
127
|
+
keys, database URL).
|
|
128
|
+
- Never print, log, or commit it, and never pass a secret as a command
|
|
129
|
+
argument. Ask the user to fill in values you do not have.
|
|
130
|
+
|
|
131
|
+
## Commands
|
|
132
|
+
|
|
133
|
+
```sh
|
|
134
|
+
# deploy to preview; the name comes from package.json
|
|
135
|
+
npx @moinulmoin/eden deploy --env-file ~/.config/<agent>/preview.env --json
|
|
136
|
+
|
|
137
|
+
# ship a change: the same command updates in place, on the same URL
|
|
138
|
+
npx @moinulmoin/eden deploy --env-file ~/.config/<agent>/preview.env --json
|
|
139
|
+
|
|
140
|
+
# production always needs an explicit --name
|
|
141
|
+
npx @moinulmoin/eden deploy --env production --name <name> --env-file <file> --json
|
|
142
|
+
|
|
143
|
+
# remove one target (always needs the exact --name deploy printed;
|
|
144
|
+
# add --env production for a production target)
|
|
145
|
+
npx @moinulmoin/eden destroy --name <name> --json
|
|
146
|
+
```
|
|
147
|
+
|
|
148
|
+
- `--project <dir>` selects a project other than the current directory.
|
|
149
|
+
- A fresh deploy takes a few minutes, mostly building the container. The
|
|
150
|
+
result's `deployment.stableWorkersDevOrigin` is the live URL.
|
|
151
|
+
- An `eve init` project's `npm run deploy` script still deploys to Vercel, not
|
|
152
|
+
Eden.
|
|
153
|
+
- Confirm with the user before any `destroy` or production deploy. Destroy
|
|
154
|
+
deletes the agent immediately, even mid-conversation, and with the Cloudflare
|
|
155
|
+
World also its stored sessions. An external Postgres database is not touched.
|
|
156
|
+
|
|
157
|
+
## Verify
|
|
158
|
+
|
|
159
|
+
Health only proves the server started; it needs no auth:
|
|
160
|
+
|
|
161
|
+
```sh
|
|
162
|
+
curl -s https://<url>/eve/v1/health # expect "status":"ready"
|
|
163
|
+
```
|
|
164
|
+
|
|
165
|
+
Then prove auth, the model key, and the agent work with a real message, using
|
|
166
|
+
the channel's credential (the bearer token from the env file):
|
|
167
|
+
|
|
168
|
+
```sh
|
|
169
|
+
curl -s -X POST https://<url>/eve/v1/session \
|
|
170
|
+
-H "Authorization: Bearer $AGENT_AUTH_TOKEN" \
|
|
171
|
+
-H "Content-Type: application/json" \
|
|
172
|
+
-d '{"message":"Reply with one word: ready"}'
|
|
173
|
+
# {"ok":true,"sessionId":"wrun_…"}; then read the reply:
|
|
174
|
+
curl -s -N https://<url>/eve/v1/session/<sessionId>/stream \
|
|
175
|
+
-H "Authorization: Bearer $AGENT_AUTH_TOKEN"
|
|
176
|
+
```
|
|
177
|
+
|
|
178
|
+
Load the token into the shell from the env file without printing it. The
|
|
179
|
+
first request after the agent sleeps takes about 10–15 seconds.
|
|
180
|
+
|
|
181
|
+
## Upgrading Eve
|
|
182
|
+
|
|
183
|
+
- Bump `eve`, then reinstall so the lockfile matches. Keep
|
|
184
|
+
`@moinulmoin/eden-world-cloudflare` on its latest version.
|
|
185
|
+
- Moving an `eve init` project to Eve `1.0` also needs `@vercel/connect`
|
|
186
|
+
`2.7.0` or later; otherwise npm fails with `ERESOLVE`.
|
|
187
|
+
- Then deploy as usual. With the current Cloudflare World, existing sessions
|
|
188
|
+
continue on the new version. With the Postgres World or an older Cloudflare
|
|
189
|
+
World they return HTTP 409 `session_stranded` and users start new ones.
|
|
190
|
+
|
|
191
|
+
## Limits to tell the user
|
|
192
|
+
|
|
193
|
+
- The sandbox is `just-bash`, a simulated shell: files, grep, sed, jq,
|
|
194
|
+
sqlite3, and curl work; python, git, and npm do not.
|
|
195
|
+
- One container per agent, `workers.dev` URL only, no custom domains yet.
|
|
196
|
+
- The container sleeps after 1 hour idle and wakes on the next request.
|
|
197
|
+
Standard 5-field cron schedules still fire while it sleeps; other cron forms
|
|
198
|
+
only fire while it is awake (`EVE_SCHEDULE_UNSUPPORTED`).
|
|
199
|
+
|
|
200
|
+
## When something fails
|
|
201
|
+
|
|
202
|
+
- Checks run before anything changes on Cloudflare. Fix the first failed
|
|
203
|
+
check by its `remediation` and run again.
|
|
204
|
+
- `VAL-CLI-007-TARGET-CONFLICT`: a resource with that name exists that Eden
|
|
205
|
+
cannot prove it owns. For a brand-new agent, pick another `--name`; never
|
|
206
|
+
delete the resource to make room.
|
|
207
|
+
- `VAL-CLI-007-CLOUDFLARE-ACCESS`: Wrangler is not logged in or the account
|
|
208
|
+
lacks Workers Paid/Containers. The user has to fix this
|
|
209
|
+
(`npx wrangler@4.147.0 whoami`).
|
|
210
|
+
- `DEPLOY_INDETERMINATE`: Eden could not prove the result; the old version
|
|
211
|
+
usually keeps serving. Check the URL's health, then retry with the exact
|
|
212
|
+
same `--project`, `--env`, and `--name`. Never switch to a new name to get
|
|
213
|
+
past it, never delete resources by prefix, and never delete the project's
|
|
214
|
+
`.eden/` folder: it is the ownership proof `destroy` needs.
|
|
215
|
+
- Look up any other code in `docs/troubleshooting.md`.
|
|
@@ -194,6 +194,24 @@ async function readInstalledManifest(snapshotRoot, packageName) {
|
|
|
194
194
|
return undefined;
|
|
195
195
|
}
|
|
196
196
|
}
|
|
197
|
+
/**
|
|
198
|
+
* Eve `1.0.0-rc.6` and later refuse to start a session unless the World
|
|
199
|
+
* admits start Hooks atomically; earlier prereleases of 1.0.0 do not ask.
|
|
200
|
+
*/
|
|
201
|
+
function eveRequiresAtomicStartHook(version) {
|
|
202
|
+
const match = typeof version === "string"
|
|
203
|
+
? /^(\d+)\.(\d+)\.(\d+)(?:-([0-9A-Za-z.-]+))?$/u.exec(version)
|
|
204
|
+
: null;
|
|
205
|
+
if (match === null)
|
|
206
|
+
return false;
|
|
207
|
+
const [major, minor, patch] = [Number(match[1]), Number(match[2]), Number(match[3])];
|
|
208
|
+
if (major !== 1 || minor !== 0 || patch !== 0)
|
|
209
|
+
return major >= 1;
|
|
210
|
+
if (match[4] === undefined)
|
|
211
|
+
return true;
|
|
212
|
+
const rc = /^rc\.(\d+)$/u.exec(match[4]);
|
|
213
|
+
return rc !== null && Number(rc[1]) >= 6;
|
|
214
|
+
}
|
|
197
215
|
/**
|
|
198
216
|
* Fails deploy/preflight when a known durable World would trip Eve's runtime
|
|
199
217
|
* World-compatibility rejection. Unreadable manifests
|
|
@@ -204,6 +222,13 @@ async function checkEveWorldPairing(candidate, world) {
|
|
|
204
222
|
world !== "@moinulmoin/eden-world-cloudflare")
|
|
205
223
|
return undefined;
|
|
206
224
|
const eveManifest = await readInstalledManifest(candidate.snapshotRoot, "eve");
|
|
225
|
+
const worldManifest = await readInstalledManifest(candidate.snapshotRoot, world);
|
|
226
|
+
if (world === "@moinulmoin/eden-world-cloudflare" &&
|
|
227
|
+
worldManifest !== undefined &&
|
|
228
|
+
eveRequiresAtomicStartHook(eveManifest?.version) &&
|
|
229
|
+
worldManifest.eden?.capabilities?.atomicStartHook !== true) {
|
|
230
|
+
return check("EVE_WORLD_PAIRING", "failed", `Eve ${eveManifest?.version} needs a World with atomic start hooks, and the installed ${world} ${worldManifest.version ?? "(unknown version)"} does not have them; every new session would fail with HTTP 500.`, `Install ${world}@0.11.1 or later; see docs/troubleshooting.md.`);
|
|
231
|
+
}
|
|
207
232
|
const expectedRange = eveManifest === undefined
|
|
208
233
|
? undefined
|
|
209
234
|
: [
|
|
@@ -215,7 +240,6 @@ async function checkEveWorldPairing(candidate, world) {
|
|
|
215
240
|
.find((value) => typeof value === "string" && value.trim().length > 0);
|
|
216
241
|
if (expectedRange === undefined)
|
|
217
242
|
return undefined;
|
|
218
|
-
const worldManifest = await readInstalledManifest(candidate.snapshotRoot, world);
|
|
219
243
|
const declared = worldManifest === undefined
|
|
220
244
|
? undefined
|
|
221
245
|
: ["@workflow/core", "@workflow/world"]
|
|
@@ -263,6 +287,56 @@ function pooledPostgresReason(connectionString) {
|
|
|
263
287
|
}
|
|
264
288
|
return undefined;
|
|
265
289
|
}
|
|
290
|
+
const EVE_WORLD_LOCAL_REMEDIATION = 'For durable state without a database, add @moinulmoin/eden-world-cloudflare and set experimental: { workflow: { world: "@moinulmoin/eden-world-cloudflare" } } in agent.ts; sessions survive Eve upgrades. Alternatively, add @workflow/world-postgres, select it as the workflow world, and put WORKFLOW_POSTGRES_URL with a direct, unpooled Postgres URL in --env-file.';
|
|
291
|
+
/** Static, dynamic, side-effect, or require imports of @vercel/connect or a subpath. */
|
|
292
|
+
function importsVercelConnect(source) {
|
|
293
|
+
return /\b(?:from|import|require)\s*\(?\s*["']@vercel\/connect(?:\/[^"']*)?["']/u
|
|
294
|
+
.test(source.replace(/\/\*[\s\S]*?\*\/|\/\/[^\n]*/gu, ""));
|
|
295
|
+
}
|
|
296
|
+
async function vercelConnectSourcePaths(projectRoot) {
|
|
297
|
+
const paths = [];
|
|
298
|
+
const visit = async (path) => {
|
|
299
|
+
const entries = await readdir(join(projectRoot, path), { withFileTypes: true })
|
|
300
|
+
.catch(() => []);
|
|
301
|
+
for (const entry of entries) {
|
|
302
|
+
if (entry.name === "node_modules" || entry.isSymbolicLink())
|
|
303
|
+
continue;
|
|
304
|
+
const child = `${path}/${entry.name}`;
|
|
305
|
+
if (entry.isDirectory())
|
|
306
|
+
await visit(child);
|
|
307
|
+
else if (entry.isFile() && /\.[cm]?[jt]sx?$/u.test(entry.name)) {
|
|
308
|
+
const source = await readFile(join(projectRoot, child), "utf8").catch(() => "");
|
|
309
|
+
if (importsVercelConnect(source))
|
|
310
|
+
paths.push(child);
|
|
311
|
+
}
|
|
312
|
+
}
|
|
313
|
+
};
|
|
314
|
+
await visit("agent");
|
|
315
|
+
await visit("agents");
|
|
316
|
+
return paths.sort();
|
|
317
|
+
}
|
|
318
|
+
/** Eve persists its compile-time routing decision, including its default model. */
|
|
319
|
+
async function collectEveGatewayWarnings(candidate, runtimeConfig) {
|
|
320
|
+
if (runtimeConfig?.withProtectedValues((values) => (values.AI_GATEWAY_API_KEY?.trim().length ?? 0) > 0) === true)
|
|
321
|
+
return [];
|
|
322
|
+
try {
|
|
323
|
+
const manifest = JSON.parse(await readFile(join(candidate.snapshotRoot, EVE_COMPILED_MANIFEST_PATH), "utf8"));
|
|
324
|
+
if (manifest?.config?.model?.routing?.kind !== "gateway")
|
|
325
|
+
return [];
|
|
326
|
+
const source = typeof manifest.config.source?.logicalPath === "string"
|
|
327
|
+
? manifest.config.source.logicalPath
|
|
328
|
+
: "agent/agent.ts";
|
|
329
|
+
return [{
|
|
330
|
+
id: "EVE_AI_GATEWAY_KEY_MISSING",
|
|
331
|
+
message: `The model in ${source} routes through Vercel AI Gateway, but --env-file has no non-blank AI_GATEWAY_API_KEY. Cloudflare has no Vercel OIDC project identity, so model calls fail.`,
|
|
332
|
+
remediation: 'Add AI_GATEWAY_API_KEY from https://vercel.com/dashboard/ai/api-keys to your --env-file, or use a direct provider such as openai("gpt-5") from @ai-sdk/openai with OPENAI_API_KEY in that file.',
|
|
333
|
+
}];
|
|
334
|
+
}
|
|
335
|
+
catch {
|
|
336
|
+
// Unknown or older compiled formats are not evidence of Gateway routing.
|
|
337
|
+
return [];
|
|
338
|
+
}
|
|
339
|
+
}
|
|
266
340
|
/**
|
|
267
341
|
* Recognizes the generated channel, not arbitrary user authentication policies.
|
|
268
342
|
* The calls below match the Eve 0.82 initializer's agent/channels/eve.ts.
|
|
@@ -277,6 +351,14 @@ async function collectEveSetupWarnings(projectRoot) {
|
|
|
277
351
|
return "";
|
|
278
352
|
}
|
|
279
353
|
};
|
|
354
|
+
const connectPaths = await vercelConnectSourcePaths(projectRoot);
|
|
355
|
+
if (connectPaths.length > 0) {
|
|
356
|
+
warnings.push({
|
|
357
|
+
id: "EVE_VERCEL_CONNECT",
|
|
358
|
+
message: `Vercel Connect imports in ${connectPaths.join(", ")} get credentials using a Vercel project identity (OIDC) that only Vercel injects; these connections fail on Cloudflare.`,
|
|
359
|
+
remediation: "Put each service's own API key or bot token in --env-file and replace connect(...) in the connection with auth: { getToken: async () => ({ token: process.env.SERVICE_TOKEN! }) }. For per-user sign-in, use defineInteractiveAuthorization from eve/connections with your own OAuth app.",
|
|
360
|
+
});
|
|
361
|
+
}
|
|
280
362
|
const channel = (await source("agent/channels/eve.ts"))
|
|
281
363
|
.replace(/\/\*[\s\S]*?\*\/|\/\/[^\n]*/gu, "")
|
|
282
364
|
.replace(/\s+/gu, "");
|
|
@@ -295,7 +377,7 @@ async function collectEveSetupWarnings(projectRoot) {
|
|
|
295
377
|
warnings.push({
|
|
296
378
|
id: "EVE_WORLD_LOCAL",
|
|
297
379
|
message: "Local World stores memory on container disk; updates or a lost sleep snapshot reset sessions and approvals.",
|
|
298
|
-
remediation:
|
|
380
|
+
remediation: EVE_WORLD_LOCAL_REMEDIATION,
|
|
299
381
|
});
|
|
300
382
|
}
|
|
301
383
|
if (manifest.dependencies?.["just-bash"] === undefined &&
|
|
@@ -350,7 +432,7 @@ async function collectEveWorldWarnings(candidate, runtimeConfig) {
|
|
|
350
432
|
warnings.push({
|
|
351
433
|
id: "EVE_WORLD_LOCAL",
|
|
352
434
|
message: "Local World stores memory on container disk; updates or a lost sleep snapshot reset sessions and approvals.",
|
|
353
|
-
remediation:
|
|
435
|
+
remediation: EVE_WORLD_LOCAL_REMEDIATION,
|
|
354
436
|
});
|
|
355
437
|
}
|
|
356
438
|
}
|
|
@@ -2412,6 +2494,7 @@ async function collectEvePreflight(request, options) {
|
|
|
2412
2494
|
if (localHint !== -1)
|
|
2413
2495
|
warnings.splice(localHint, 1);
|
|
2414
2496
|
warnings.push(...(await collectEveWorldWarnings(candidate, undefined)));
|
|
2497
|
+
warnings.push(...await collectEveGatewayWarnings(candidate, runtimeConfig));
|
|
2415
2498
|
const schedules = await readCompiledSchedules(candidate);
|
|
2416
2499
|
const expressible = schedules.filter((schedule) => parseEveScheduleCron(schedule.cron) !== undefined);
|
|
2417
2500
|
const unexpressible = schedules.filter((schedule) => parseEveScheduleCron(schedule.cron) === undefined);
|
package/dist/index.js
CHANGED
|
@@ -17,6 +17,7 @@ Commands:
|
|
|
17
17
|
preflight Build and inspect a local Eve candidate without remote mutation
|
|
18
18
|
deploy Deploy the selected Eve project to the exact named target
|
|
19
19
|
destroy Remove the exact owned Eve target
|
|
20
|
+
skill Print the bundled Eden skill for coding agents
|
|
20
21
|
|
|
21
22
|
preflight and deploy default to the current directory, the preview
|
|
22
23
|
environment, and a target name derived from package.json. destroy and
|
|
@@ -177,6 +178,24 @@ export async function runEdenCli(args, options = {}) {
|
|
|
177
178
|
stdout(edenVersion());
|
|
178
179
|
return 0;
|
|
179
180
|
}
|
|
181
|
+
if (args[0] === "skill") {
|
|
182
|
+
if (args.length === 2 && (args[1] === "--help" || args[1] === "-h")) {
|
|
183
|
+
stdout("Usage: eden skill");
|
|
184
|
+
return 0;
|
|
185
|
+
}
|
|
186
|
+
if (args.length !== 1) {
|
|
187
|
+
throw new EveCliError({
|
|
188
|
+
code: "EVE_ARGUMENT_UNKNOWN",
|
|
189
|
+
message: "eden skill takes no arguments or options.",
|
|
190
|
+
});
|
|
191
|
+
}
|
|
192
|
+
const skill = readFileSync(new URL("./SKILL.md", import.meta.url), "utf8");
|
|
193
|
+
if (options.stdout === undefined)
|
|
194
|
+
process.stdout.write(skill);
|
|
195
|
+
else
|
|
196
|
+
options.stdout(skill);
|
|
197
|
+
return 0;
|
|
198
|
+
}
|
|
180
199
|
if (!EVE_CLI_COMMANDS.includes(args[0] ?? "")) {
|
|
181
200
|
throw new EveCliError({
|
|
182
201
|
code: "COMMAND_UNKNOWN",
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@moinulmoin/eden",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.11.1",
|
|
4
4
|
"description": "Deploy existing Eve projects to your own Cloudflare account.",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"ai",
|
|
@@ -27,11 +27,12 @@
|
|
|
27
27
|
"dist/**/*.js",
|
|
28
28
|
"dist/**/*.mjs",
|
|
29
29
|
"dist/**/*.d.ts",
|
|
30
|
+
"dist/SKILL.md",
|
|
30
31
|
"LICENSE",
|
|
31
32
|
"NOTICE"
|
|
32
33
|
],
|
|
33
34
|
"dependencies": {
|
|
34
|
-
"@moinulmoin/eden-runtime-cloudflare": "0.
|
|
35
|
+
"@moinulmoin/eden-runtime-cloudflare": "0.11.1",
|
|
35
36
|
"wrangler": "4.147.0"
|
|
36
37
|
},
|
|
37
38
|
"devDependencies": {
|
|
@@ -54,7 +55,7 @@
|
|
|
54
55
|
},
|
|
55
56
|
"scripts": {
|
|
56
57
|
"build": "tsc -b",
|
|
57
|
-
"postbuild": "chmod 755 dist/index.js",
|
|
58
|
+
"postbuild": "chmod 755 dist/index.js && cp ../../skills/eden/SKILL.md dist/SKILL.md",
|
|
58
59
|
"typecheck": "tsc -b --pretty false",
|
|
59
60
|
"lint": "eslint src --max-warnings 0",
|
|
60
61
|
"test": "pnpm --dir ../.. exec vitest run packages/cli/test --passWithNoTests --maxWorkers=1"
|