@open-everywhere/create 0.4.0 → 0.5.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/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@open-everywhere/create",
3
- "version": "0.4.0",
3
+ "version": "0.5.0",
4
4
  "license": "Apache-2.0",
5
5
  "type": "module",
6
6
  "description": "npx scaffold and setup check for Open Everywhere — one step engine, reported by --check for an agent-led setup.",
@@ -46,8 +46,8 @@
46
46
  "test:env-pipe": "tsx scripts/env-pipe-test.ts"
47
47
  },
48
48
  "dependencies": {
49
- "@open-everywhere/core": "0.4.0",
50
- "@open-everywhere/provider-slack": "0.4.0",
49
+ "@open-everywhere/core": "0.5.0",
50
+ "@open-everywhere/provider-slack": "0.5.0",
51
51
  "tsx": "^4.23.9"
52
52
  },
53
53
  "devDependencies": {
@@ -0,0 +1,44 @@
1
+ // The A2A AGENTS this app declares (OPE-2425) — config-as-code, changed by pull request only.
2
+ //
3
+ // MCP servers (./mcp-servers.ts) give the agent TOOLS AND DATA. A2A agents give it OTHER AGENTS: a
4
+ // focused enterprise agent — an Agentforce, ServiceNow, Workday or Copilot Studio agent — that takes a
5
+ // whole task in plain language and reports back. Each entry here is one such agent:
6
+ // • The agent reads the entry's published AGENT CARD and reaches ONLY the card URL's origin (scheme,
7
+ // host and port). A card that names an endpoint anywhere else is refused.
8
+ // • `delegate_to_agent` sends it a task. Every delegation takes an approval first: a member's click on
9
+ // a card that shows the agent, its host and the exact task text, or a pre-approval rule or the
10
+ // approval judge. The task goes out with the asker's identity attached
11
+ // (platform, workspace and their verified id) in the message metadata, with the person who approved
12
+ // it, or the rule that lifted it.
13
+ // • What the agent answers is UNTRUSTED content: it is fenced like any connector result, and it taints
14
+ // the turn that reads it.
15
+ //
16
+ // Only an INTERNAL room may delegate: a shared (Slack Connect), public or guest room is refused, and so
17
+ // is a request a guest or external account took part in. `domains` narrows it further.
18
+ //
19
+ // A person cannot add an agent: a name that is not in this list is refused. No secret goes in this
20
+ // file — an agent that needs a token names its credential-store REF (`npx oe secret set <ref>`).
21
+ // See docs/extending/a2a-agents.md.
22
+
23
+ import { defineA2aAgents } from "@open-everywhere/core/agent/a2a/agents.js";
24
+
25
+ export const A2A_AGENTS = defineA2aAgents([
26
+ // Example — an agent with a public card and no credential:
27
+ //
28
+ // {
29
+ // name: "it-helpdesk",
30
+ // cardUrl: "https://<the vendor's agent host>/.well-known/agent-card.json",
31
+ // description: "The IT helpdesk agent: opens, reads and updates IT tickets for a person.",
32
+ // },
33
+ //
34
+ // Example — an agent that takes a bearer token. Store the token with `npx oe secret set <ref>` and
35
+ // name the REF here, never the value:
36
+ //
37
+ // {
38
+ // name: "hr-agent",
39
+ // cardUrl: "https://agents.hr.example/.well-known/agent-card.json",
40
+ // description: "The HR agent: answers questions about leave, payroll dates and benefits.",
41
+ // auth: { scheme: "bearer", secretRef: "db:a2a:hr-agent-token" },
42
+ // domains: ["people-ops"], // optional: only conversations in these memory domains may use it
43
+ // },
44
+ ]);
@@ -30,6 +30,7 @@ import { emptyAgentsFile } from "@open-everywhere/core/agent/memory/agents-codem
30
30
  import { loadBaseBundles, loadBaseBindings } from "./bundles.js";
31
31
  import { loadBaseConnectorCredentials } from "./connector-credentials.js";
32
32
  import { loadBaseWebhooks } from "../webhooks/hooks.js";
33
+ import { MCP_SERVERS } from "./mcp-servers.js";
33
34
  import { loadBaseDomains, loadBaseSilos, loadDomains } from "../memory/config/domains.js";
34
35
  import { loadGroups } from "../identity/groups.js";
35
36
 
@@ -61,6 +62,8 @@ export function loadAccessRequests(): AccessRequestsConfig | null {
61
62
  // baseline a candidate overlay is validated against before any PR opens.
62
63
  hooksPath: process.env.OE_WEBHOOK_HOOKS_PATH || undefined,
63
64
  baseWebhooks: loadBaseWebhooks,
65
+ // The declared MCP servers, so `propose_mcp_server` validates a candidate entry against them (OPE-2420).
66
+ baseMcpServers: () => MCP_SERVERS,
64
67
  // The `create_agent` PR path (create_agent flow, increment 2) rides this SAME config repo, branch
65
68
  // and bot credential — only the machine-written file differs (the agents overlay). `baseAgents` is
66
69
  // the code-declared agents baseline (empty — agents live only in the overlay); `baseDomains` /
@@ -16,10 +16,23 @@
16
16
  // which needs no client id and no secret. Only a vendor WITHOUT dynamic registration takes a static
17
17
  // client, and then this file names the secret's credential-store REF, never its value.
18
18
  // See docs/extending/connectors.md#declare-an-mcp-server-in-your-app.
19
+ //
20
+ // "SEARCH SLACK AS YOU" (OPE-2421) is a built-in entry: `slackAsYou({ clientId })` mounts Slack's own MCP
21
+ // server on each person's own Slack sign-in, in their Slack DM only. The agent answers with the bot first and
22
+ // offers the person's connection only when the bot cannot see what was asked; every post as the person takes a
23
+ // card. It reuses the org's own Slack app: name its public Client ID here, and store its Client Secret with
24
+ // `npx oe secret set db:slack:oauth-client-secret`. The Slack app also needs the MCP toggle (its Agents section)
25
+ // and the scopes in the manifest `surface_manifest` returns once this entry is declared.
26
+ // See docs/deploy/surfaces/slack.md#search-slack-as-you.
19
27
 
20
28
  import { defineMcpServers } from "@open-everywhere/core/agent/connections/mcp-servers.js";
21
29
 
22
30
  export const MCP_SERVERS = defineMcpServers([
31
+ // Example — "search Slack as you" on your own Slack app. Import it first:
32
+ // import { slackAsYou } from "@open-everywhere/provider-slack/agent/slack-as-you.js";
33
+ //
34
+ // slackAsYou({ clientId: "<your Slack app's Client ID>" }),
35
+ //
23
36
  // Example — a vendor with dynamic client registration (the common case). Take the URL from the
24
37
  // vendor's own MCP documentation:
25
38
  //
@@ -27,6 +40,9 @@ export const MCP_SERVERS = defineMcpServers([
27
40
  // name: "fullstory",
28
41
  // url: "https://<the vendor's hosted MCP endpoint>",
29
42
  // description: "FullStory: search sessions, read session summaries and product analytics.",
43
+ // // Optional. The OAuth scopes the sign-in asks for; absent ⇒ no scope parameter is sent and the
44
+ // // vendor's default applies. Name the read scopes first: a person's token holds only these.
45
+ // signIn: { scopes: ["read:sessions"] },
30
46
  // },
31
47
  //
32
48
  // Example — a vendor WITHOUT dynamic registration. Create the client in the vendor's developer
@@ -43,6 +59,7 @@ export const MCP_SERVERS = defineMcpServers([
43
59
  // clientId: "public-client-id",
44
60
  // clientSecretRef: "db:acme:oauth-client-secret",
45
61
  // bodyEncoding: "form",
62
+ // scopes: ["accounts.read", "deals.read"], // optional: the scopes the authorize URL asks for
46
63
  // },
47
64
  // },
48
65
  ]);
@@ -72,6 +72,10 @@ set up, they just ask. Pick the move that fits the shape of the ask:
72
72
  offer to set it up with `create_routine` so it just happens without anyone asking.
73
73
  - **Make it a skill.** A multi-step way-of-doing-things recurs: capture it with
74
74
  `create_skill` so next time it's one named move.
75
+ - **Set up a new connector.** "Set up FullStory" or "connect <vendor>" asks for a NEW connector, and that is
76
+ a pull request, not a grant. A worker researches the vendor's hosted MCP server (`web_search`,
77
+ `web_fetch`) and proposes it with `propose_mcp_server`: one entry in `agent/access/mcp-servers.ts`
78
+ on the deployment's config repo, for an admin to merge. It is not set up until the merge.
75
79
 
76
80
  Some of these verbs live on workers rather than on a conversational seat. If a move above
77
81
  names a tool you don't hold, that is not a "can't" — delegate it (`agent`) with a brief
@@ -40,6 +40,8 @@ import { loadSpendCheckpoints } from "../spend/checkpoints.js";
40
40
  import { loadModelPolicy } from "../model/policy.js";
41
41
  import { loadPrincipals } from "../identity/principals.js";
42
42
  import { loadGroups } from "../identity/groups.js";
43
+ import { registerA2aAgents } from "@open-everywhere/core/agent/a2a/agents.js";
44
+ import { A2A_AGENTS } from "../access/a2a-agents.js";
43
45
  // Side effect: register the operator's per-surface trust registry (identity/trust.ts) at
44
46
  // boot, before any binding resolves. Self-registering (calls registerSurfaces on
45
47
  // import); nothing to thread through the AppConfig object.
@@ -96,6 +98,12 @@ registerSettings(SETTINGS_OVERRIDES);
96
98
  // prices during boot sees a half-wired deployment.
97
99
  registerModelPricing(loadModelPricing());
98
100
 
101
+ // The A2A AGENTS this app declares (OPE-2425, agent/access/a2a-agents.ts) — the only agents
102
+ // `delegate_to_agent` can reach. Registered on core's own slot rather than carried on AppConfig: the
103
+ // list is validated at import (defineA2aAgents throws on a bad entry), and an unregistered list is
104
+ // empty, so a core-only process delegates to nobody.
105
+ registerA2aAgents(A2A_AGENTS);
106
+
99
107
  registerConfig({
100
108
  loadBundles,
101
109
  loadBindings,
@@ -70,6 +70,12 @@
70
70
  // Every member outside Slack must be declared internal in agent/identity/surfaces.ts, or the boot
71
71
  // refuses the window (memory/domain.ts assertWindowSourcesVouched).
72
72
  //
73
+ // 🔴 THE DEFAULT IS UNIFIED. A declared domain that omits `mode` shares ONE window across its
74
+ // rooms (OPE-2412). It falls back to solo, and the boot logs why, when its reach holds a tenant or
75
+ // glob entry or a room outside Slack is not declared internal. A one-room domain stays solo. To
76
+ // keep each room in its own seat, write `mode: "solo"` on the domain. `org`, `public` and `dm`
77
+ // below are always solo.
78
+ //
73
79
  // --- CRITERIA PSEUDO-DOMAINS (optional) — selected by trust/mode, not a channel list.
74
80
  // Each is a singleton (at most one per match) with the full domain toolkit.
75
81
  //
@@ -2,8 +2,8 @@
2
2
  // inbound-webhook surface (docs/capabilities/proactivity-and-routines.md in the Open Everywhere repository "Inbound
3
3
  // webhook triggers"). Declare a hook: which signature scheme its sender uses (`source`),
4
4
  // where its shared secret lives (`secretRef` + the `broker` that ref resolves through),
5
- // which `slack/TEAM/CHANNEL` surface it fires into, and what the agent should do when it
6
- // fires. Point the provider at `POST /webhooks/<id>` (channels/webhooks.ts).
5
+ // where it fires (a room on Slack, Discord or Teams, or a person's DM), and what the agent
6
+ // should do when it fires. Point the provider at `POST /webhooks/<id>` (channels/webhooks.ts).
7
7
  //
8
8
  // SIGNATURE SCHEME: `source` names the registered verifier. `"oe-standard-webhook"` is
9
9
  // OUR own contract — the public standard-webhooks spec (`webhook-id` + `webhook-timestamp`
@@ -50,8 +50,8 @@
50
50
  // the seam a DB/dashboard would swap behind, same as memory/config/domains.ts and access/
51
51
  // bundles.ts. After adding a hook: `npm run typecheck` plus a boot (assertWebhooksValid runs
52
52
  // at import time and throws on a malformed entry — id collisions, a missing source, a
53
- // blank/empty secretRef, a missing broker, a target that isn't a well-formed
54
- // slack/TEAM/CHANNEL triple).
53
+ // blank/empty secretRef, a missing broker, a target that is neither a room
54
+ // "<platform>/<workspace>/<surface>" nor a person "dm:<principal key>").
55
55
 
56
56
  import { defineWebhook, assertWebhooksValid, type WebhookHook } from "@open-everywhere/core/agent/webhooks/config.js";
57
57
  import { loadHooksOverlay } from "./hooks-overlay.js";
@@ -64,7 +64,7 @@ const hooks: WebhookHook[] = [
64
64
  // source: "oe-standard-webhook", // OUR contract — a sender you control signs it
65
65
  // secretRef: "DEPLOY_STATUS_WEBHOOK_SECRET", // shared secret REF (env var NAME here, not the value)
66
66
  // broker: "env", // the home that ref resolves through ("env" | "db" | ...)
67
- // target: "slack/<team-id>/<channel-id>", // fully-qualified slack/TEAM/CHANNEL surface
67
+ // target: "slack/<team-id>/<channel-id>", // a room on any surface, or "dm:<principal key>" for a person
68
68
  // readableBy: [{ level: "domain", domain: "engineering" }], // WHO may read its events — REQUIRED, no default
69
69
  // posture: "projection", // HOW MUCH of the payload reaches the model
70
70
  // project: ["status", "branch"], // …under "projection": exactly these normalizer field keys
@@ -58,10 +58,12 @@
58
58
  "hook/spend": "mounted",
59
59
  "hook/stall-guard": "mounted",
60
60
  "hook/telemetry": "mounted",
61
+ "hook/tool-usage": "mounted",
61
62
  "hook/turn-anchor": "mounted",
62
63
  "hook/wake-accounting-turn": "mounted",
63
64
  "hook/wake-turn-start": "mounted",
64
65
  "hook/window-routing": "mounted",
66
+ "schedule/audit-export": "mounted",
65
67
  "schedule/directory-sync": "mounted",
66
68
  "schedule/dispatch": "mounted",
67
69
  "schedule/dream-mode3": "mounted",
@@ -78,6 +80,7 @@
78
80
  "tool/cancel_routine": "mounted",
79
81
  "tool/cancel_work": "mounted",
80
82
  "tool/capture_events": "mounted",
83
+ "tool/check_agent_task": "mounted",
81
84
  "tool/check_pr_status": "mounted",
82
85
  "tool/checkout_repo": "mounted",
83
86
  "tool/clear_connector_override": "mounted",
@@ -91,6 +94,7 @@
91
94
  "tool/create_skill": "mounted",
92
95
  "tool/create_ticket": "mounted",
93
96
  "tool/declare_webhook": "mounted",
97
+ "tool/delegate_to_agent": "mounted",
94
98
  "tool/delete_skill": "mounted",
95
99
  "tool/describe_image": "mounted",
96
100
  "tool/dm_person": "mounted",
@@ -116,6 +120,7 @@
116
120
  "tool/post_file": "mounted",
117
121
  "tool/post_message": "mounted",
118
122
  "tool/post_pr_walkthrough": "mounted",
123
+ "tool/propose_mcp_server": "mounted",
119
124
  "tool/purge_memory": "mounted",
120
125
  "tool/query_analytics": "mounted",
121
126
  "tool/react": "mounted",
@@ -156,6 +161,7 @@
156
161
  "tool/unlink_identity": "mounted",
157
162
  "tool/update_status": "mounted",
158
163
  "tool/usage_report": "mounted",
164
+ "tool/waiting_on_me": "mounted",
159
165
  "tool/walk_pr": "mounted",
160
166
  "tool/work": "mounted"
161
167
  }
@@ -44,11 +44,13 @@ agent/hooks/spawn-taint.ts mounted @open-everywhere/core
44
44
  agent/hooks/spend.ts mounted @open-everywhere/core
45
45
  agent/hooks/stall-guard.ts mounted @open-everywhere/core
46
46
  agent/hooks/telemetry.ts mounted @open-everywhere/core
47
+ agent/hooks/tool-usage.ts mounted @open-everywhere/core
47
48
  agent/hooks/turn-anchor.ts mounted @open-everywhere/core
48
49
  agent/hooks/wake-accounting-turn.ts mounted @open-everywhere/core
49
50
  agent/hooks/wake-turn-start.ts mounted @open-everywhere/core
50
51
  agent/hooks/window-routing.ts mounted @open-everywhere/core
51
52
  agent/lib/providers.generated.ts providers slack,notion,github
53
+ agent/schedules/audit-export.ts mounted @open-everywhere/core
52
54
  agent/schedules/directory-sync.ts mounted @open-everywhere/core
53
55
  agent/schedules/dispatch.ts mounted @open-everywhere/core
54
56
  agent/schedules/dream-mode3.ts mounted @open-everywhere/core
@@ -67,6 +69,7 @@ agent/tools/browser_tools.ts mounted @open-everywhere/core
67
69
  agent/tools/cancel_routine.ts mounted @open-everywhere/core
68
70
  agent/tools/cancel_work.ts mounted @open-everywhere/core
69
71
  agent/tools/capture_events.ts mounted @open-everywhere/core
72
+ agent/tools/check_agent_task.ts mounted @open-everywhere/core
70
73
  agent/tools/check_pr_status.ts mounted @open-everywhere/core
71
74
  agent/tools/checkout_repo.ts mounted @open-everywhere/core
72
75
  agent/tools/clear_connector_override.ts mounted @open-everywhere/core
@@ -80,6 +83,7 @@ agent/tools/create_routine.ts mounted @open-everywhere/core
80
83
  agent/tools/create_skill.ts mounted @open-everywhere/core
81
84
  agent/tools/create_ticket.ts mounted @open-everywhere/core
82
85
  agent/tools/declare_webhook.ts mounted @open-everywhere/core
86
+ agent/tools/delegate_to_agent.ts mounted @open-everywhere/core
83
87
  agent/tools/delete_skill.ts mounted @open-everywhere/core
84
88
  agent/tools/describe_image.ts mounted @open-everywhere/core
85
89
  agent/tools/dm_person.ts mounted @open-everywhere/core
@@ -107,6 +111,7 @@ agent/tools/permission_fit_report.ts mounted @open-everywhere/core
107
111
  agent/tools/post_file.ts mounted @open-everywhere/core
108
112
  agent/tools/post_message.ts mounted @open-everywhere/core
109
113
  agent/tools/post_pr_walkthrough.ts mounted @open-everywhere/core
114
+ agent/tools/propose_mcp_server.ts mounted @open-everywhere/core
110
115
  agent/tools/purge_memory.ts mounted @open-everywhere/core
111
116
  agent/tools/query_analytics.ts mounted @open-everywhere/core
112
117
  agent/tools/react.ts mounted @open-everywhere/core
@@ -150,6 +155,7 @@ agent/tools/subscribe_pr.ts mounted @open-everywhere/core
150
155
  agent/tools/unlink_identity.ts mounted @open-everywhere/core
151
156
  agent/tools/update_status.ts mounted @open-everywhere/core
152
157
  agent/tools/usage_report.ts mounted @open-everywhere/core
158
+ agent/tools/waiting_on_me.ts mounted @open-everywhere/core
153
159
  agent/tools/walk_pr.ts mounted @open-everywhere/core
154
160
  agent/tools/web_fetch.ts framework-disabled
155
161
  agent/tools/work.ts mounted @open-everywhere/core