eve-hub 0.6.7 → 0.6.9

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 CHANGED
@@ -1,5 +1,17 @@
1
1
  # eve-hub
2
2
 
3
+ ## 0.6.9
4
+
5
+ ### Patch Changes
6
+
7
+ - A hosted deployment reaches GitHub one way for every bot: `gh` and `git` in bash through the sandbox firewall token, with eve's git extension mounted on each bot. The build no longer wires in the Vercel Kit connection (`GITHUB_PATH` in `github-path.mjs` is the one switch; `"kit"` brings it back).
8
+
9
+ ## 0.6.8
10
+
11
+ ### Patch Changes
12
+
13
+ - The bots' world folds eve's session-limit requests into the hosted hub, so a session parked on its input limit shows its Approve/Stop ask to the human.
14
+
3
15
  ## 0.6.7
4
16
 
5
17
  ### Patch Changes
@@ -0,0 +1 @@
1
+ export const GITHUB_PATH: "gh" | "kit";
@@ -0,0 +1,8 @@
1
+ // How every deployed bot reaches GitHub, decided here and nowhere else:
2
+ // "gh" `gh` and `git` in bash (the firewall token and eve's git extension, both
3
+ // always on, prepare.mjs); no Vercel Kit connection, so no bot can pick
4
+ // Kit for GitHub, and onboarding sets up no Kit connector.
5
+ // "kit" the same, plus the Kit connection on every bot (prepare.mjs, and the
6
+ // peer dependencies it needs in hosted-hub/scripts/stage-workspace.mjs) and
7
+ // the Kit connector on each new bots project (hosted-hub/src/onboard/provision-steps.ts).
8
+ export const GITHUB_PATH = "gh";
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "eve-hub",
3
- "version": "0.6.7",
3
+ "version": "0.6.9",
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
@@ -9,7 +9,8 @@
9
9
  // pays for model calls) with only the kit stubs that run off the hub's
10
10
  // machine (DEPLOYED_KIT_FILES);
11
11
  // - the kit extension, host-only workers and kit stubs are dropped, the hub's
12
- // workflow world and the Vercel Kit connection are wired in, and the
12
+ // workflow world is wired in (and the Vercel Kit connection, if GITHUB_PATH
13
+ // says "kit"), every bot gets eve's git extension, and the
13
14
  // workspace's memory is embedded in the bots' memory providers (a function
14
15
  // has no workspace cwd);
15
16
  // - /hub/manifest: the roster and the commit sha the deployment was built
@@ -17,6 +18,7 @@
17
18
  // vercel.mjs. Bearer BOT_TOKEN, as on each bot's eve channel (bot-token.mjs).
18
19
  import { existsSync, mkdirSync, readdirSync, readFileSync, rmSync, rmdirSync, unlinkSync, writeFileSync } from "node:fs";
19
20
  import { basename, dirname, join } from "node:path";
21
+ import { GITHUB_PATH } from "./github-path.mjs";
20
22
  import { KIT_FILES, MAIN_KIT_FILES } from "./stubs.mjs";
21
23
  import { deploymentFacts, hostedContext } from "./execution-context.mjs";
22
24
  import { botDomains, domainFolders, readBotMemory, readMemory, validateMemory } from "./memory.mjs";
@@ -84,11 +86,14 @@ export const VERCEL_SANDBOX = vercelSandbox("");
84
86
  // The builder's sandbox also carries eve-code's tooling (agents/builder/agent/extensions/code/).
85
87
  export const CODE_SANDBOX = vercelSandbox("\n await installCodeTooling(sandbox);");
86
88
 
89
+ // eve's git extension, for every bot: it points the bot at `gh` and `git` in
90
+ // bash, whose GitHub credential is the sandbox firewall's (VERCEL_SANDBOX above).
91
+ // With no `github` option it brokers no credential. It only guides: its `pr`
92
+ // skill (commit, push, draft PR) loads when a bot publishes.
93
+ export const gitExtensionFiles = () => ({ "extensions/git/extension.ts": `import git from "eve/extensions/git";\n\nexport default git({});\n` });
94
+
87
95
  // Bots that edit code: eve-code (apply_patch, grep, the review skills and its
88
- // read-only worker) plus eve's git extension, both with no `github` option. The
89
- // git extension then points the bot at `gh` and `git` in bash, whose GitHub
90
- // credential is the sandbox firewall's (VERCEL_SANDBOX above), and its `pr` skill
91
- // is the plain commit, push and draft-PR one. The worker runs on the roster's
96
+ // read-only worker), with no `github` option. The worker runs on the roster's
92
97
  // subagent cap like every other subagent, not on eve's built-in default.
93
98
  export const CODE_BOTS = ["builder"];
94
99
  export const codeExtensionFiles = (bot) => ({
@@ -102,7 +107,6 @@ const { model, reasoning } = resolveSubagent(agents, subagentCap, ${JSON.stringi
102
107
 
103
108
  export default code({ worker: { model, reasoning } });
104
109
  `,
105
- "extensions/git/extension.ts": `import git from "eve/extensions/git";\n\nexport default git({});\n`,
106
110
  });
107
111
 
108
112
  const KIT_VERSION = JSON.parse(readFileSync(new URL("./package.json", import.meta.url), "utf8")).version;
@@ -188,11 +192,9 @@ export function prepareDeployment(dir) {
188
192
  const name = basename(dirname(bot));
189
193
  const code = CODE_BOTS.includes(name);
190
194
  writeFileSync(join(bot, "sandbox.ts"), code ? CODE_SANDBOX : VERCEL_SANDBOX);
191
- if (code) {
192
- for (const [stub, content] of Object.entries(codeExtensionFiles(name))) {
193
- mkdirSync(dirname(join(bot, stub)), { recursive: true });
194
- writeFileSync(join(bot, stub), content);
195
- }
195
+ for (const [stub, content] of Object.entries({ ...gitExtensionFiles(), ...(code ? codeExtensionFiles(name) : {}) })) {
196
+ mkdirSync(dirname(join(bot, stub)), { recursive: true });
197
+ writeFileSync(join(bot, stub), content);
196
198
  }
197
199
  }
198
200
  const roster = resolved.agents;
@@ -207,10 +209,12 @@ export function prepareDeployment(dir) {
207
209
  }
208
210
  const agentFile = join(bot, "agent.ts");
209
211
  writeFileSync(agentFile, injectWorkflowWorld(readFileSync(agentFile, "utf8"), agentFile));
210
- // Hosted bots reach the human's connected services (GitHub) through Vercel Kit,
211
- // with the project's KIT_CONNECTOR; there is no host credential to fall back on.
212
- mkdirSync(join(bot, "connections"), { recursive: true });
213
- writeFileSync(join(bot, "connections", "vercel-kit.ts"), 'export { default } from "eve-hub/connections/vercel-kit";\n');
212
+ // GITHUB_PATH "kit": the human's connected services (GitHub) come through Vercel Kit,
213
+ // with the project's KIT_CONNECTOR. "gh" deploys no Kit connection.
214
+ if (GITHUB_PATH === "kit") {
215
+ mkdirSync(join(bot, "connections"), { recursive: true });
216
+ writeFileSync(join(bot, "connections", "vercel-kit.ts"), 'export { default } from "eve-hub/connections/vercel-kit";\n');
217
+ }
214
218
  mkdirSync(join(bot, "memory"), { recursive: true });
215
219
  const botDir = join(dir, "agents", name);
216
220
  writeFileSync(join(bot, "memory", "workspace.ts"), memoryProvider("workspace", readMemory(dir, { folders: domainFolders(botDomains(dir, botDir)) }).entries, "Standing decision", "workspace"));
package/world.mjs CHANGED
@@ -564,6 +564,12 @@ var APP_READS = [
564
564
  ...DASH_READS
565
565
  ];
566
566
 
567
+ // ../../hosted-hub/src/store/requests.ts
568
+ var PENDING_REQUESTS_READ = s(`SELECT r.id, r.session_id, r.thread_id, r.bot, r.kind, r.prompt, r.options, r.allow_freeform, r.tool_name, r.submitted_at, r.created_at,
569
+ (SELECT d.message_id FROM turn_deliveries td JOIN deliveries d ON d.id = td.delivery_id WHERE td.turn_id = r.turn_id ORDER BY d.rowid DESC LIMIT 1) AS message_id
570
+ FROM input_requests r JOIN sessions s ON s.id = r.session_id
571
+ WHERE r.status = 'pending' AND s.ended_at IS NULL ORDER BY r.created_at`);
572
+
567
573
  // ../../hosted-hub/src/store/workspace-state.ts
568
574
  var LIVE_TURNS_READ = s(`SELECT thread_id,bot,started_at,reply_text,activity FROM turns WHERE status IN ${OPEN_TURN_STATUSES} ORDER BY started_at`);
569
575
 
@@ -27031,6 +27037,20 @@ function fold(state, chunks, now = Date.now()) {
27031
27037
  for (const [eventIndex, event] of events.entries()) {
27032
27038
  const data = event.data ?? {};
27033
27039
  at = Date.parse(event.meta?.at ?? "") || now;
27040
+ if (event.type === "input.requested") {
27041
+ const limits = (data.requests ?? []).filter((r) => r.kind === "session-limit");
27042
+ for (const r of limits)
27043
+ stmts.push(s(`INSERT OR IGNORE INTO input_requests (id, session_id, thread_id, bot, turn_id, kind, prompt, options, allow_freeform, tool_name, created_at)
27044
+ VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)`, r.requestId, session.id, session.thread, session.bot, open3?.id ?? null, r.kind, r.prompt, JSON.stringify(r.options ?? []), r.allowFreeform ? 1 : 0, r.action?.toolName ?? null, at));
27045
+ if (limits.length) log("request.updated", { requestIds: limits.map((r) => r.requestId) });
27046
+ }
27047
+ if (event.type === "input.resolved") {
27048
+ for (const r of data.resolutions ?? [])
27049
+ stmts.push(s(`UPDATE input_requests SET status = 'resolved', outcome = ?, resolved_at = ?,
27050
+ answer = COALESCE(?, (SELECT json_extract(o.value, '$.label') FROM json_each(input_requests.options) o WHERE json_extract(o.value, '$.id') = ?), ?)
27051
+ WHERE id = ? AND session_id = ? AND status = 'pending'`, r.outcome ?? "answered", at, r.response?.text ?? null, r.response?.optionId ?? null, r.response?.optionId ?? null, r.requestId, session.id));
27052
+ log("request.updated", { requestIds: (data.resolutions ?? []).map((r) => r.requestId) });
27053
+ }
27034
27054
  if (event.type === "turn.started") {
27035
27055
  if (!data.turnId) throw new Error("turn.started must name eve turnId");
27036
27056
  flush();