eve-hub 0.6.12 → 0.6.14
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/CHANGELOG.md +12 -0
- package/README.md +1 -1
- package/memory.mjs +1 -1
- package/package.json +1 -1
- package/prepare.mjs +8 -51
- package/templates/execution-context-hosted-main.md +1 -1
- package/templates/workspace-protocol.md +1 -1
- package/tools/create_agent.d.ts +4 -2
- package/tools/create_agent.js +2 -1
package/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,17 @@
|
|
|
1
1
|
# eve-hub
|
|
2
2
|
|
|
3
|
+
## 0.6.14
|
|
4
|
+
|
|
5
|
+
### Patch Changes
|
|
6
|
+
|
|
7
|
+
- `create_agent` takes `runsOn`: a bot is created with the sandbox of where it runs, and the hosted build no longer writes sandboxes. Hosted main can create a bot by committing it to the workspace repository; it joins with the next deployment.
|
|
8
|
+
|
|
9
|
+
## 0.6.13
|
|
10
|
+
|
|
11
|
+
### Patch Changes
|
|
12
|
+
|
|
13
|
+
- The workspace protocol says an attached image shows as an image tile on its own, so bots stop writing `![]()` for it.
|
|
14
|
+
|
|
3
15
|
## 0.6.12
|
|
4
16
|
|
|
5
17
|
### Patch Changes
|
package/README.md
CHANGED
|
@@ -61,7 +61,7 @@ A deployed workspace (lib/workspace-template.mjs, staged by hosted-hub/scripts/s
|
|
|
61
61
|
|
|
62
62
|
Releases go through Changesets, as in eve. A PR that changes the kit adds a changeset (`pnpm changeset`) and applies it (`pnpm changeset version`); when it merges, `.github/workflows/release.yml` runs `changeset publish` (no bot commits to main: its ruleset allows only PR merges): the kit's `prepack` stages the package into `dist/npm` (its `publishConfig.directory`), npm gets it, and the `eve-hub@<version>` GitHub release is created. npm auth is the repo's `NPM_TOKEN` secret (an npm automation token). The template pins the version this checkout carries.
|
|
63
63
|
|
|
64
|
-
The template's main gets a Vercel Sandbox and only the kit stubs that run without the hub's machine (lib/workspace-template.mjs `DEPLOYED_KIT_FILES`; eve's own bash replaces the kit's). The template's builder also mounts eve-code (`eve/extensions/code`: `apply_patch`, `grep`, the review skills, a read-only worker) and `eve/extensions/git` (`git({})`), both with no `github` option. The bot uses `gh` and `git` from bash, whose GitHub token is the sandbox firewall's (`
|
|
64
|
+
The template's main gets a Vercel Sandbox and only the kit stubs that run without the hub's machine (lib/workspace-template.mjs `DEPLOYED_KIT_FILES`; eve's own bash replaces the kit's). The template's builder also mounts eve-code (`eve/extensions/code`: `apply_patch`, `grep`, the review skills, a read-only worker) and `eve/extensions/git` (`git({})`), both with no `github` option. The bot uses `gh` and `git` from bash, whose GitHub token is the sandbox firewall's (the Vercel sandbox `create_agent` writes, lib/agent-template.mjs `sandboxFile`), and no `gh` tool is contributed. A deployed workspace's eve is the one pin in `hosted-hub/bots/package.json`, which staging copies over the template's (an eve snapshot with both `eve/world-hub` and `eve/extensions/git`; `hosted-hub/test/stage-workspace.test.mjs` checks the staged imports resolve against it). The hub and local bots stay on the hub's eve. The published tarball (`scripts/pack.mjs`) leaves out the kit__worker extension, which mounts only on the hub's machine. The hub reaches each bot's eve channel with `Authorization: Bearer $BOT_TOKEN` (`bot-token.mjs`); the kit's calls to the hub (`registry-fetch.mjs`, at `ROSTER_REGISTRY_URL`) carry `Authorization: Bearer $HUB_TOKEN` and, since the hosted hub keeps Vercel Authentication on, `x-vercel-protection-bypass: $HUB_PROTECTION_BYPASS` (the hub project's automation bypass secret), each when set.
|
|
65
65
|
|
|
66
66
|
## Vercel Kit connection
|
|
67
67
|
|
package/memory.mjs
CHANGED
|
@@ -235,7 +235,7 @@ const warnOnce = (msg) => {
|
|
|
235
235
|
const unreadableIds = (errors) => new Set(errors.map((e) => /(?:^|\/)memory\/(?:[^/:]+\/)*([^/:]+)\.md:/.exec(e)?.[1]).filter(Boolean));
|
|
236
236
|
|
|
237
237
|
// `domains`: the bot's domains (hub.workspace.json), see the header.
|
|
238
|
-
export function loadMemoryRecall(root, history = [], { warn = warnOnce, domains = [] } = {}) {
|
|
238
|
+
export function loadMemoryRecall(root, history = [], { warn = warnOnce, domains = /** @type {string[]} */ ([]) } = {}) {
|
|
239
239
|
const { entries, errors } = readMemory(root, { folders: domainFolders(domains) });
|
|
240
240
|
for (const error of errors) warn(error);
|
|
241
241
|
return memoryRecall(entries, history, { unreadable: unreadableIds(errors) });
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "eve-hub",
|
|
3
|
-
"version": "0.6.
|
|
3
|
+
"version": "0.6.14",
|
|
4
4
|
"license": "Apache-2.0",
|
|
5
5
|
"description": "Bot-side code shared by every hub agent: registry tools, the roster hook, the eve channel, the host sandbox and browser, and model helpers.",
|
|
6
6
|
"type": "module",
|
package/prepare.mjs
CHANGED
|
@@ -5,9 +5,10 @@
|
|
|
5
5
|
// - bots marked `runsOn: "local"` are the Mac runner's: their folders and
|
|
6
6
|
// roster entries leave the hosted build, after hub.manifest.json records the
|
|
7
7
|
// whole roster for the hub;
|
|
8
|
-
// - each bot runs in
|
|
9
|
-
// pays for model calls) with only the kit stubs that run
|
|
10
|
-
// machine (DEPLOYED_KIT_FILES);
|
|
8
|
+
// - each bot runs in the Vercel Sandbox its creation wrote (the project's OIDC
|
|
9
|
+
// token opens it and pays for model calls) with only the kit stubs that run
|
|
10
|
+
// off the hub's machine (DEPLOYED_KIT_FILES); a hosted bot whose sandbox.ts
|
|
11
|
+
// is the host's fails the build, and the build never writes a sandbox;
|
|
11
12
|
// - the kit extension, host-only workers and kit stubs are dropped, the hub's
|
|
12
13
|
// workflow world is wired in (and the Vercel Kit connection, if GITHUB_PATH
|
|
13
14
|
// says "kit"), every bot gets eve's git extension, and the
|
|
@@ -33,62 +34,19 @@ import { agentRunsOn, readWorkspaceFile, removeWorkspaceAgent } from "./workspac
|
|
|
33
34
|
// instead), the browser and the screenshot paths of attach_image/view_image,
|
|
34
35
|
// the mention gate (the
|
|
35
36
|
// daemon's per-process HUB_AGENT and patched model credential), the tools that
|
|
36
|
-
//
|
|
37
|
-
//
|
|
37
|
+
// remove or restart bots on the hub's disk (a deployment changes its roster by
|
|
38
|
+
// commit; create_agent is that commit, made by the hosted hub), memory (the workspace's files), and main's schedules.
|
|
38
39
|
export const DEPLOYED_KIT_FILES = new Set([
|
|
39
40
|
"channels/eve.ts",
|
|
40
41
|
"skills/onboarding-profile.ts",
|
|
41
42
|
"tools/onboarding_scripts.ts",
|
|
42
43
|
...["react", "show", "update_thread", "list_threads", "read_thread", "post_message"].map((t) => `tools/${t}.ts`),
|
|
43
|
-
...["create_thread", "set_summary", "move_path", "archive_thread", "unarchive_thread", "list_agents", "agent_send", "tag_threads", "dash_update", "apply_tags"].map((t) => `tools/${t}.ts`),
|
|
44
|
+
...["create_thread", "set_summary", "move_path", "archive_thread", "unarchive_thread", "list_agents", "agent_send", "create_agent", "tag_threads", "dash_update", "apply_tags"].map((t) => `tools/${t}.ts`),
|
|
44
45
|
]);
|
|
45
46
|
|
|
46
47
|
|
|
47
|
-
const vercelSandbox = (prepare) => `import { defineSandbox } from "eve/sandbox";
|
|
48
|
-
import { VercelSandbox } from "eve/sandbox/vercel";
|
|
49
|
-
${prepare ? 'import { installCodeTooling } from "eve/extensions/code/sandbox";\n' : ""}
|
|
50
|
-
// TEMPORARY (until the Vercel Connect GitHub connector replaces it): the
|
|
51
|
-
// project's GITHUB_TOKEN is added to GitHub requests by the sandbox firewall,
|
|
52
|
-
// so the token never enters the sandbox. api.github.com (gh, REST) takes
|
|
53
|
-
// Bearer; github.com (git over HTTPS) takes Basic. Unset: no policy.
|
|
54
|
-
const token = process.env.GITHUB_TOKEN;
|
|
55
|
-
const networkPolicy = token ? { allow: {
|
|
56
|
-
"api.github.com": [{ transform: [{ headers: { authorization: "Bearer " + token } }] }],
|
|
57
|
-
"github.com": [{ transform: [{ headers: { authorization: "Basic " + Buffer.from("x-access-token:" + token).toString("base64") } }] }],
|
|
58
|
-
"*": [],
|
|
59
|
-
} } : undefined;
|
|
60
|
-
|
|
61
|
-
// A Vercel Sandbox, opened with the project's OIDC token.
|
|
62
|
-
export const environment = VercelSandbox.environment({ networkPolicy, prepare: async (sandbox) => {${prepare}
|
|
63
|
-
const run = async (command, what) => {
|
|
64
|
-
if ((await sandbox.run({ command })).exitCode !== 0) throw new Error(what + " failed");
|
|
65
|
-
};
|
|
66
|
-
if (!token) return;
|
|
67
|
-
// eve's sandbox image is Ubuntu with git only; gh and ssh-keygen come from apt.
|
|
68
|
-
await run("sudo apt-get update -qq && sudo apt-get install -y -qq gh openssh-client", "gh and ssh installation");
|
|
69
|
-
// gh refuses to run without a login; this one is a placeholder the firewall overwrites.
|
|
70
|
-
await run("mkdir -p ~/.config/gh && printf 'github.com:\\n user: hub\\n oauth_token: placeholder\\n git_protocol: https\\n' > ~/.config/gh/hosts.yml", "gh login");
|
|
71
|
-
// The org requires signed commits. Eve reuses a named template sandbox after a failed prepare, so
|
|
72
|
-
// this step starts by clearing an earlier key. A key made here, registered as a signing key on
|
|
73
|
-
// the token's user, never leaves the sandbox; commits carry that user's noreply email.
|
|
74
|
-
await run([
|
|
75
|
-
"mkdir -p ~/.ssh && rm -f ~/.ssh/signing ~/.ssh/signing.pub && ssh-keygen -q -t ed25519 -N '' -C hub-bot -f ~/.ssh/signing",
|
|
76
|
-
"gh api user/ssh_signing_keys -f title=\\\"hub bot sandbox $(date -u +%FT%TZ)\\\" -f key=\\\"$(cat ~/.ssh/signing.pub)\\\" --silent",
|
|
77
|
-
"login=$(gh api user --jq .login) && id=$(gh api user --jq .id)",
|
|
78
|
-
"git config --global user.name \\\"$login\\\" && git config --global user.email \\\"$id+$login@users.noreply.github.com\\\"",
|
|
79
|
-
"git config --global gpg.format ssh && git config --global user.signingkey ~/.ssh/signing && git config --global commit.gpgsign true",
|
|
80
|
-
].join(" && "), "git signing setup");
|
|
81
|
-
} });
|
|
82
|
-
export default defineSandbox(() => environment.open());
|
|
83
|
-
`;
|
|
84
|
-
|
|
85
|
-
export const VERCEL_SANDBOX = vercelSandbox("");
|
|
86
|
-
|
|
87
|
-
// The builder's sandbox also carries eve-code's tooling (agents/builder/agent/extensions/code/).
|
|
88
|
-
export const CODE_SANDBOX = vercelSandbox("\n await installCodeTooling(sandbox);");
|
|
89
|
-
|
|
90
48
|
// eve's git extension, for every bot: it points the bot at `gh` and `git` in
|
|
91
|
-
// bash, whose GitHub credential is the sandbox firewall's (
|
|
49
|
+
// bash, whose GitHub credential is the sandbox firewall's (the Vercel sandbox lib/agent-template.mjs writes).
|
|
92
50
|
// With no `github` option it brokers no credential. It only guides: its `pr`
|
|
93
51
|
// skill (commit, push, draft PR) loads when a bot publishes.
|
|
94
52
|
export const gitExtensionFiles = () => ({ "extensions/git/extension.ts": `import git from "eve/extensions/git";\n\nexport default git({});\n` });
|
|
@@ -193,7 +151,6 @@ export function prepareDeployment(dir) {
|
|
|
193
151
|
if (existsSync(join(bot, "schedules/learning-review.ts"))) removeStub(bot, "schedules/learning-review.ts");
|
|
194
152
|
const name = basename(dirname(bot));
|
|
195
153
|
const code = CODE_BOTS.includes(name);
|
|
196
|
-
writeFileSync(join(bot, "sandbox.ts"), code ? CODE_SANDBOX : VERCEL_SANDBOX);
|
|
197
154
|
for (const [stub, content] of Object.entries({ ...gitExtensionFiles(), ...(code ? codeExtensionFiles(name) : {}) })) {
|
|
198
155
|
mkdirSync(dirname(join(bot, stub)), { recursive: true });
|
|
199
156
|
writeFileSync(join(bot, stub), content);
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
- **Team.**
|
|
1
|
+
- **Team.** `create_agent` takes `runsOn` (`hosted` or `local`) and commits the new bot to the workspace repository; it joins with the next deployment, and a `local` bot then runs on the owner's Mac. There is no `remove_agent`: the roster is `hub.workspace.json`, and a deployment changes it by commit. If nobody on the team covers the work well, ask the human before going on.
|
|
2
2
|
- **Restarts.** There is no `restart_agent` or `restart_hub`: you cannot restart a bot or the hub. A new deployment replaces the running bots.
|
|
3
3
|
- **Memory.** Add an entry as your Memory section says, by committing the file to the workspace repository (see Changing it above). With no repository, write nothing and tell the human to link one first.
|
|
4
4
|
- **Schedules.** The build removes the kit's schedules (`dash`, `compact`, `prune`), so no classifier runs, no tick posts, and nothing rewrites track summaries. What you write with `set_summary` and `dash_update` stands until you change it.
|
|
@@ -88,7 +88,7 @@ renders as:
|
|
|
88
88
|
- `---` with a blank line on both sides starts a new bubble. Without the blank line above, it makes the line before it a heading.
|
|
89
89
|
- Each top-level code fence is a card with a language label and a copy icon; each table is a table card. Inline code has no copy icon, so anything the reader will paste goes in a fence. Cards wrap rather than scroll: keep command lines short.
|
|
90
90
|
- A link is a gray chip with an icon and its label, so labels are short nouns (`#412`, `Feed.swift:1015`). A bare URL shows only its hostname.
|
|
91
|
-
- An attached image shows as an image tile
|
|
91
|
+
- An attached image shows as an image tile on its own; never write `![]()` for it; raw HTML shows literally.
|
|
92
92
|
- Nothing collapses, and the Mentions inbox previews only the first plain-text line of each message. So each message's first bubble is its point, in at most 2 sentences; detail follows after `---`.
|
|
93
93
|
- Separate updates (started, found, done) are separate posts; `---` splits one message into bubbles.
|
|
94
94
|
- Tables only for 2+ rows of short, comparable values: at most 4 columns sharing the width equally, a few words per cell. A single item, or anything that needs a reason, goes in a sentence or bullets. Shorten shas to 8 characters; keep URLs and paths in link text, not cells.
|
package/tools/create_agent.d.ts
CHANGED
|
@@ -2,26 +2,28 @@ declare const _default: import("eve/tools").ToolDefinition<{
|
|
|
2
2
|
name: string;
|
|
3
3
|
model: string;
|
|
4
4
|
reasoning?: "high" | "low" | "medium" | "xhigh" | undefined;
|
|
5
|
+
runsOn?: "hosted" | "local" | undefined;
|
|
5
6
|
role: string;
|
|
6
7
|
instructions?: string | undefined;
|
|
7
8
|
domains?: string[] | undefined;
|
|
8
9
|
preset?: "builder" | "read-only" | undefined;
|
|
9
10
|
}, {
|
|
10
11
|
name: string;
|
|
11
|
-
port
|
|
12
|
+
port?: number;
|
|
12
13
|
status: string;
|
|
13
14
|
}> & {
|
|
14
15
|
execute(input: {
|
|
15
16
|
name: string;
|
|
16
17
|
model: string;
|
|
17
18
|
reasoning?: "high" | "low" | "medium" | "xhigh" | undefined;
|
|
19
|
+
runsOn?: "hosted" | "local" | undefined;
|
|
18
20
|
role: string;
|
|
19
21
|
instructions?: string | undefined;
|
|
20
22
|
domains?: string[] | undefined;
|
|
21
23
|
preset?: "builder" | "read-only" | undefined;
|
|
22
24
|
}, ctx: import("eve/tools").ToolContext): Promise<{
|
|
23
25
|
name: string;
|
|
24
|
-
port
|
|
26
|
+
port?: number;
|
|
25
27
|
status: string;
|
|
26
28
|
}>;
|
|
27
29
|
};
|
package/tools/create_agent.js
CHANGED
|
@@ -4,11 +4,12 @@ import { registryFetch } from "../registry-fetch.mjs";
|
|
|
4
4
|
// Adds a named bot to the workspace: scaffolds agents/<name>/, registers it,
|
|
5
5
|
// starts it, and opens its DM. Returns once the bot is healthy.
|
|
6
6
|
export default defineTool({
|
|
7
|
-
description: "Create a new named bot in the workspace.
|
|
7
|
+
description: "Create a new named bot in the workspace. In a local workspace it joins the team immediately and can be @-mentioned once this returns. In a hosted workspace this commits the bot to the workspace repo, and it joins with the next deployment, hosted or on the Mac alike. Models are AI Gateway ids, e.g. openai/gpt-6-luna, anthropic/claude-opus-5.5.",
|
|
8
8
|
inputSchema: z.object({
|
|
9
9
|
name: z.string().regex(/^[a-z][a-z0-9-]{1,30}$/).describe("Lowercase handle, e.g. deep-diver."),
|
|
10
10
|
model: z.string().describe("AI Gateway model id."),
|
|
11
11
|
reasoning: z.enum(["low", "medium", "high", "xhigh"]).optional(),
|
|
12
|
+
runsOn: z.enum(["hosted", "local"]).optional().describe("Where the bot runs, fixed for its life: hosted (the Vercel bots project) or local (the human's Mac). Required in a hosted workspace; a local workspace's bots are local."),
|
|
12
13
|
role: z.string().describe("One line: what this bot does."),
|
|
13
14
|
instructions: z.string().optional().describe("Extra guidance: specialty, style, who it hands off to."),
|
|
14
15
|
domains: z.array(z.string().regex(/^[a-z][a-z0-9-]*(\/[a-z][a-z0-9-]*)*$/)).optional().describe("Memory domains: folders under memory/ whose standing decisions this bot also recalls, e.g. [\"ui\"]. It always recalls memory/ itself."),
|