@cursor/july 0.1.62 → 0.1.73
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/AGENTS.md +4 -5
- package/README.md +23 -11
- package/dist/bin/agent-serve.js +11 -2
- package/dist/channels/github/api.d.ts +2 -0
- package/dist/channels/github/api.d.ts.map +1 -1
- package/dist/channels/github/api.js +2 -1
- package/dist/channels/github/binding.d.ts +7 -0
- package/dist/channels/github/binding.d.ts.map +1 -1
- package/dist/channels/github/binding.js +4 -0
- package/dist/channels/github/checks.d.ts +99 -0
- package/dist/channels/github/checks.d.ts.map +1 -0
- package/dist/channels/github/checks.js +108 -0
- package/dist/channels/github/cursor-account.d.ts +4 -4
- package/dist/channels/github/cursor-account.d.ts.map +1 -1
- package/dist/channels/github/cursor-account.js +7 -5
- package/dist/channels/github/index.d.ts +1 -0
- package/dist/channels/github/index.d.ts.map +1 -1
- package/dist/channels/github/index.js +1 -0
- package/dist/channels/github/types.d.ts +8 -0
- package/dist/channels/github/types.d.ts.map +1 -1
- package/dist/channels/slack/channel-watch.d.ts +2 -1
- package/dist/channels/slack/channel-watch.d.ts.map +1 -1
- package/dist/channels/slack/channel-watch.js +7 -3
- package/dist/channels/slack/dispatch.d.ts +9 -0
- package/dist/channels/slack/dispatch.d.ts.map +1 -1
- package/dist/channels/slack/dispatch.js +41 -21
- package/dist/channels/slack/manifest.d.ts +2 -2
- package/dist/channels/slack/manifest.d.ts.map +1 -1
- package/dist/channels/slack/manifest.js +14 -11
- package/dist/channels/slack/nudge-store.d.ts +16 -0
- package/dist/channels/slack/nudge-store.d.ts.map +1 -1
- package/dist/channels/slack/nudge-store.js +53 -0
- package/dist/channels/slack/slack-channel.d.ts.map +1 -1
- package/dist/channels/slack/slack-channel.js +4 -1
- package/dist/channels/slack/types.d.ts +24 -7
- package/dist/channels/slack/types.d.ts.map +1 -1
- package/dist/connections.d.ts +17 -5
- package/dist/connections.d.ts.map +1 -1
- package/dist/connections.js +17 -5
- package/dist/docs/404.html +2 -2
- package/dist/docs/ab.html +3 -3
- package/dist/docs/assets/{app.B-biogkN.js → app.CdbcFD8T.js} +1 -1
- package/dist/docs/assets/chunks/@localSearchIndexroot.DQad--_z.js +1 -0
- package/dist/docs/assets/chunks/{VPLocalSearchBox.DZqKtFZS.js → VPLocalSearchBox.D_NKImM7.js} +1 -1
- package/dist/docs/assets/chunks/{theme.BwC5zP2r.js → theme.CMvz7cu9.js} +2 -2
- package/dist/docs/assets/{concepts.md.CqOsxbMU.js → concepts.md.BXAm6G-C.js} +1 -1
- package/dist/docs/assets/{guides_mcp-oauth.md.C7G7IykG.js → guides_mcp-oauth.md.CzEB6RaG.js} +1 -1
- package/dist/docs/assets/{reference_agent-config.md.DHkkvcEZ.js → reference_agent-config.md.BZnEKfEc.js} +3 -4
- package/dist/docs/assets/{reference_agent-config.md.DHkkvcEZ.lean.js → reference_agent-config.md.BZnEKfEc.lean.js} +1 -1
- package/dist/docs/assets/{reference_connections.md.CSQiNzre.js → reference_connections.md.Cu3N-S3Q.js} +26 -9
- package/dist/docs/assets/reference_connections.md.Cu3N-S3Q.lean.js +1 -0
- package/dist/docs/assets/{reference_sessions.md.DBVFi2Sx.js → reference_sessions.md.B0DdlM-K.js} +1 -1
- package/dist/docs/assets/{reference_tools.md.kJfJAP2m.js → reference_tools.md.DTg_kEsx.js} +2 -2
- package/dist/docs/assets/{reference_tools.md.kJfJAP2m.lean.js → reference_tools.md.DTg_kEsx.lean.js} +1 -1
- package/dist/docs/assets/troubleshooting.md.DQ-hYuZT.js +1 -0
- package/dist/docs/building-with-agents.html +3 -3
- package/dist/docs/concepts.html +5 -5
- package/dist/docs/deployment.html +3 -3
- package/dist/docs/evals.html +3 -3
- package/dist/docs/example-agents/approval-buddy.html +3 -3
- package/dist/docs/example-agents/benny.html +3 -3
- package/dist/docs/example-agents/bugbot.html +3 -3
- package/dist/docs/example-agents/codebase-wiki.html +3 -3
- package/dist/docs/example-agents/codeowners-review.html +3 -3
- package/dist/docs/example-agents/concierge.html +3 -3
- package/dist/docs/example-agents/fsd.html +3 -3
- package/dist/docs/example-agents/index.html +3 -3
- package/dist/docs/example-agents/knowledge-base.html +3 -3
- package/dist/docs/example-agents/oncall.html +3 -3
- package/dist/docs/example-agents/security-reviewer.html +3 -3
- package/dist/docs/example-agents/slack-agent.html +3 -3
- package/dist/docs/example-agents/weather-agent.html +3 -3
- package/dist/docs/guides/agent-to-agent.html +3 -3
- package/dist/docs/guides/cloud-runtime.html +3 -3
- package/dist/docs/guides/convert-automation.html +3 -3
- package/dist/docs/guides/github.html +3 -3
- package/dist/docs/guides/human-in-the-loop.html +3 -3
- package/dist/docs/guides/mcp-oauth.html +5 -5
- package/dist/docs/guides/opentelemetry.html +3 -3
- package/dist/docs/guides/slack.html +3 -3
- package/dist/docs/guides/webhooks.html +3 -3
- package/dist/docs/hashmap.json +1 -1
- package/dist/docs/hillclimbing.html +3 -3
- package/dist/docs/index.html +3 -3
- package/dist/docs/quickstart.html +3 -3
- package/dist/docs/reference/agent-config.html +5 -6
- package/dist/docs/reference/artifacts.html +3 -3
- package/dist/docs/reference/channels.html +3 -3
- package/dist/docs/reference/cli.html +3 -3
- package/dist/docs/reference/connections.html +28 -11
- package/dist/docs/reference/hooks.html +3 -3
- package/dist/docs/reference/http-api.html +3 -3
- package/dist/docs/reference/instructions.html +3 -3
- package/dist/docs/reference/playground.html +3 -3
- package/dist/docs/reference/project-layout.html +3 -3
- package/dist/docs/reference/prompt.html +3 -3
- package/dist/docs/reference/schedules.html +3 -3
- package/dist/docs/reference/sessions.html +5 -5
- package/dist/docs/reference/skills.html +3 -3
- package/dist/docs/reference/subagents.html +3 -3
- package/dist/docs/reference/tools.html +5 -5
- package/dist/docs/scaffolding-agents.html +3 -3
- package/dist/docs/storage.html +3 -3
- package/dist/docs/templates/agentic-owners.html +3 -3
- package/dist/docs/templates/demo.html +3 -3
- package/dist/docs/templates/pr-autofixer.html +3 -3
- package/dist/docs/templates/security-reviewer.html +3 -3
- package/dist/docs/templates/triage.html +3 -3
- package/dist/docs/troubleshooting.html +5 -5
- package/dist/files-backends/agent-store-presigned-url.js +1 -1
- package/dist/index.d.ts +2 -2
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +1 -1
- package/dist/internal/advertise-tools.d.ts +79 -0
- package/dist/internal/advertise-tools.d.ts.map +1 -0
- package/dist/internal/advertise-tools.js +185 -0
- package/dist/internal/cli-deploy.d.ts.map +1 -1
- package/dist/internal/cli-deploy.js +7 -1
- package/dist/internal/cli-manifest.d.ts +19 -0
- package/dist/internal/cli-manifest.d.ts.map +1 -0
- package/dist/internal/cli-manifest.js +49 -0
- package/dist/internal/cli-slack.d.ts.map +1 -1
- package/dist/internal/cli-slack.js +9 -1
- package/dist/internal/convert-automation/convert-workflow.d.ts.map +1 -1
- package/dist/internal/convert-automation/convert-workflow.js +2 -10
- package/dist/internal/cursor/account-mcp.d.ts +29 -3
- package/dist/internal/cursor/account-mcp.d.ts.map +1 -1
- package/dist/internal/cursor/account-mcp.js +147 -67
- package/dist/internal/cursor/backend-client.d.ts +11 -6
- package/dist/internal/cursor/backend-client.d.ts.map +1 -1
- package/dist/internal/cursor/backend-client.js +32 -10
- package/dist/internal/cursor-account-mcp-auth.d.ts +11 -0
- package/dist/internal/cursor-account-mcp-auth.d.ts.map +1 -1
- package/dist/internal/cursor-account-mcp-auth.js +69 -0
- package/dist/internal/cursor-agent-template.d.ts +9 -0
- package/dist/internal/cursor-agent-template.d.ts.map +1 -0
- package/dist/internal/cursor-agent-template.js +37 -0
- package/dist/internal/deploy-client.d.ts +1 -0
- package/dist/internal/deploy-client.d.ts.map +1 -1
- package/dist/internal/deploy-client.js +18 -2
- package/dist/internal/deploy-manifest.d.ts +76 -0
- package/dist/internal/deploy-manifest.d.ts.map +1 -0
- package/dist/internal/deploy-manifest.js +117 -0
- package/dist/internal/deployment-scm-event-stream.d.ts +116 -0
- package/dist/internal/deployment-scm-event-stream.d.ts.map +1 -0
- package/dist/internal/deployment-scm-event-stream.js +474 -0
- package/dist/internal/discovery.d.ts.map +1 -1
- package/dist/internal/discovery.js +111 -10
- package/dist/internal/init-project.d.ts.map +1 -1
- package/dist/internal/init-project.js +12 -123
- package/dist/internal/init-scaffold.d.ts +8 -0
- package/dist/internal/init-scaffold.d.ts.map +1 -0
- package/dist/internal/init-scaffold.js +168 -0
- package/dist/internal/inline-stdio-mcp.d.ts +2 -0
- package/dist/internal/inline-stdio-mcp.d.ts.map +1 -1
- package/dist/internal/inline-stdio-mcp.js +10 -8
- package/dist/internal/json-schema.d.ts +7 -0
- package/dist/internal/json-schema.d.ts.map +1 -1
- package/dist/internal/json-schema.js +18 -3
- package/dist/internal/mcp-endpoint.js +7 -7
- package/dist/internal/mcp-host.d.ts +18 -0
- package/dist/internal/mcp-host.d.ts.map +1 -1
- package/dist/internal/mcp-host.js +43 -5
- package/dist/internal/mcp-oauth.d.ts +22 -0
- package/dist/internal/mcp-oauth.d.ts.map +1 -1
- package/dist/internal/mcp-oauth.js +40 -1
- package/dist/internal/package-inline-stdio.d.ts.map +1 -1
- package/dist/internal/package-inline-stdio.js +5 -5
- package/dist/internal/review-comments.d.ts +97 -0
- package/dist/internal/review-comments.d.ts.map +1 -1
- package/dist/internal/review-comments.js +151 -0
- package/dist/internal/sanitize-mcp-tool-name.d.ts +20 -0
- package/dist/internal/sanitize-mcp-tool-name.d.ts.map +1 -0
- package/dist/internal/sanitize-mcp-tool-name.js +30 -0
- package/dist/internal/sdk-runner.d.ts +1 -1
- package/dist/internal/sdk-runner.d.ts.map +1 -1
- package/dist/internal/sdk-runner.js +36 -13
- package/dist/internal/server.d.ts.map +1 -1
- package/dist/internal/server.js +18 -0
- package/dist/internal/session-engine.d.ts +66 -0
- package/dist/internal/session-engine.d.ts.map +1 -1
- package/dist/internal/session-engine.js +428 -110
- package/dist/internal/shallow-clone.d.ts +170 -0
- package/dist/internal/shallow-clone.d.ts.map +1 -0
- package/dist/internal/shallow-clone.js +412 -0
- package/dist/internal/slack-provision-client.d.ts +2 -0
- package/dist/internal/slack-provision-client.d.ts.map +1 -1
- package/dist/internal/slack-provision-client.js +1 -0
- package/dist/internal/terminal-style.d.ts +18 -0
- package/dist/internal/terminal-style.d.ts.map +1 -1
- package/dist/internal/terminal-style.js +46 -1
- package/dist/internal/turn-lease-store.d.ts +44 -0
- package/dist/internal/turn-lease-store.d.ts.map +1 -0
- package/dist/internal/turn-lease-store.js +139 -0
- package/dist/internal/workspace.d.ts +14 -0
- package/dist/internal/workspace.d.ts.map +1 -1
- package/dist/internal/workspace.js +33 -0
- package/dist/playground/assets/index-77uhu5Kr.css +1 -0
- package/dist/playground/assets/index-D4buox4m.js +85 -0
- package/dist/playground/index.html +2 -2
- package/dist/storage-protocol.d.ts +122 -0
- package/dist/storage-protocol.d.ts.map +1 -0
- package/dist/storage-protocol.js +173 -0
- package/dist/storage.d.ts +2 -72
- package/dist/storage.d.ts.map +1 -1
- package/dist/storage.js +2 -82
- package/dist/tools.d.ts +7 -0
- package/dist/tools.d.ts.map +1 -1
- package/dist/types.d.ts +141 -6
- package/dist/types.d.ts.map +1 -1
- package/docs/concepts.md +4 -4
- package/docs/guides/mcp-oauth.md +3 -1
- package/docs/reference/agent-config.md +11 -12
- package/docs/reference/connections.md +108 -10
- package/docs/reference/sessions.md +2 -2
- package/docs/reference/tools.md +14 -0
- package/docs/troubleshooting.md +3 -2
- package/package.json +7 -2
- package/skills/create-agent/SKILL.md +12 -9
- package/skills/debug/SKILL.md +2 -1
- package/skills/framework-map/SKILL.md +6 -6
- package/skills/mcp-auth/SKILL.md +8 -6
- package/src/bin/agent-serve.ts +12 -2
- package/src/channels/github/api.ts +6 -1
- package/src/channels/github/binding.ts +21 -0
- package/src/channels/github/checks.ts +179 -0
- package/src/channels/github/cursor-account.ts +9 -6
- package/src/channels/github/index.ts +1 -0
- package/src/channels/github/types.ts +8 -0
- package/src/channels/slack/channel-watch.ts +6 -3
- package/src/channels/slack/dispatch.ts +40 -3
- package/src/channels/slack/manifest.ts +9 -10
- package/src/channels/slack/nudge-store.ts +56 -0
- package/src/channels/slack/slack-channel.ts +3 -0
- package/src/channels/slack/types.ts +24 -7
- package/src/connections.ts +17 -5
- package/src/index.ts +5 -0
- package/src/internal/advertise-tools.ts +278 -0
- package/src/internal/cli-deploy.ts +11 -1
- package/src/internal/cli-manifest.ts +63 -0
- package/src/internal/cli-slack.ts +10 -1
- package/src/internal/convert-automation/convert-workflow.ts +2 -11
- package/src/internal/cursor/account-mcp.ts +208 -73
- package/src/internal/cursor/backend-client.ts +45 -11
- package/src/internal/cursor-account-mcp-auth.ts +83 -0
- package/src/internal/cursor-agent-template.ts +46 -0
- package/src/internal/deploy-client.ts +25 -6
- package/src/internal/deploy-manifest.ts +161 -0
- package/src/internal/deployment-scm-event-stream.ts +593 -0
- package/src/internal/discovery.ts +132 -3
- package/src/internal/init-project.ts +18 -153
- package/src/internal/init-scaffold.ts +176 -0
- package/src/internal/inline-stdio-mcp.ts +13 -0
- package/src/internal/json-schema.ts +24 -3
- package/src/internal/mcp-endpoint.ts +6 -0
- package/src/internal/mcp-host.ts +70 -9
- package/src/internal/mcp-oauth.ts +55 -1
- package/src/internal/package-inline-stdio.ts +5 -1
- package/src/internal/review-comments.ts +245 -0
- package/src/internal/sanitize-mcp-tool-name.ts +33 -0
- package/src/internal/sdk-runner.ts +50 -11
- package/src/internal/server.ts +19 -0
- package/src/internal/session-engine.ts +392 -19
- package/src/internal/shallow-clone.ts +595 -0
- package/src/internal/slack-provision-client.ts +3 -0
- package/src/internal/terminal-style.ts +67 -1
- package/src/internal/turn-lease-store.ts +147 -0
- package/src/internal/workspace.ts +33 -0
- package/src/storage-protocol.ts +247 -0
- package/src/storage.ts +16 -110
- package/src/tools.ts +7 -0
- package/src/types.ts +149 -7
- package/templates/agentic-owners/agent/agent.ts +3 -0
- package/templates/demo/agent/agent.ts +3 -0
- package/templates/pr-autofixer/agent/lib/drive-schemas.ts +4 -1
- package/templates/security-reviewer/agent/agent.ts +3 -0
- package/templates/triage/agent/agent.ts +3 -0
- package/dist/docs/assets/chunks/@localSearchIndexroot.5ozYNf74.js +0 -1
- package/dist/docs/assets/reference_connections.md.CSQiNzre.lean.js +0 -1
- package/dist/docs/assets/troubleshooting.md.CuVztCKs.js +0 -1
- package/dist/playground/assets/index-B4rcOgeP.css +0 -1
- package/dist/playground/assets/index-DXcY42Jv.js +0 -85
- /package/dist/docs/assets/{concepts.md.CqOsxbMU.lean.js → concepts.md.BXAm6G-C.lean.js} +0 -0
- /package/dist/docs/assets/{guides_mcp-oauth.md.C7G7IykG.lean.js → guides_mcp-oauth.md.CzEB6RaG.lean.js} +0 -0
- /package/dist/docs/assets/{reference_sessions.md.DBVFi2Sx.lean.js → reference_sessions.md.B0DdlM-K.lean.js} +0 -0
- /package/dist/docs/assets/{troubleshooting.md.CuVztCKs.lean.js → troubleshooting.md.DQ-hYuZT.lean.js} +0 -0
|
@@ -0,0 +1,278 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Advertised connection tools (`defineConnection({ advertiseTools: true })`).
|
|
3
|
+
*
|
|
4
|
+
* The session engine calls {@link resolveAdvertisedTools} while building
|
|
5
|
+
* every local turn: for each advertising connection it lists the server's
|
|
6
|
+
* tools and synthesizes a named 1:1 passthrough server tool per entry —
|
|
7
|
+
* the server's own names, descriptions, and live schemas — merged into the
|
|
8
|
+
* authored `agent/tools/` catalog. Because it runs at turn-build time it
|
|
9
|
+
* covers every way a turn starts (dispatcher sends, follow-ups, reminder
|
|
10
|
+
* fires that call the engine directly) and survives process restarts,
|
|
11
|
+
* since nothing is parked in memory between turns.
|
|
12
|
+
*
|
|
13
|
+
* Connections with per-session `auth` are listed and called through a
|
|
14
|
+
* one-off client carrying that session's headers (the registry's cached
|
|
15
|
+
* per-name client would leak one session's identity into another);
|
|
16
|
+
* auth-less connections go through the shared `host.mcp` registry, which
|
|
17
|
+
* also covers serve-resolved transports (Cursor account bridges, peers).
|
|
18
|
+
*
|
|
19
|
+
* Advertised names follow the Cursor-account MCP bridge
|
|
20
|
+
* (`packages/agent-serve/src/internal/cursor/account-mcp.ts`): slug
|
|
21
|
+
* `[^a-zA-Z0-9_-]` to `_`, collision suffixes `_2` / `_3`, and call the
|
|
22
|
+
* original advertised name. That is the same mapping `packages/agent`
|
|
23
|
+
* `normalizeMcpToolName` uses for IDE/Sand MCP tools. A listing failure
|
|
24
|
+
* still fails the turn rather than running it with a silently shrunken
|
|
25
|
+
* toolset.
|
|
26
|
+
*/
|
|
27
|
+
|
|
28
|
+
import type {
|
|
29
|
+
DiscoveredConnection,
|
|
30
|
+
DiscoveredTool,
|
|
31
|
+
HostMcpCallResult,
|
|
32
|
+
HostMcpToolInfo,
|
|
33
|
+
JsonSchemaObject,
|
|
34
|
+
ResolvedAgent,
|
|
35
|
+
SessionInfo,
|
|
36
|
+
ToolDefinition,
|
|
37
|
+
} from "../types.js";
|
|
38
|
+
import { brandDefinition } from "./brand.js";
|
|
39
|
+
import type { HostMcpOneOff } from "./mcp-host.js";
|
|
40
|
+
import {
|
|
41
|
+
sanitizeMcpToolName,
|
|
42
|
+
suffixMcpToolName,
|
|
43
|
+
} from "./sanitize-mcp-tool-name.js";
|
|
44
|
+
|
|
45
|
+
/**
|
|
46
|
+
* What the resolver needs from the host MCP registry: the shared cached
|
|
47
|
+
* clients for auth-less connections, and one-off clients (per-session
|
|
48
|
+
* headers, never cached) for auth'd ones. `McpHost` implements this.
|
|
49
|
+
*/
|
|
50
|
+
export interface AdvertiseHostMcp {
|
|
51
|
+
listTools(connectionName: string): Promise<HostMcpToolInfo[]>;
|
|
52
|
+
callTool(
|
|
53
|
+
connectionName: string,
|
|
54
|
+
toolName: string,
|
|
55
|
+
args?: Record<string, unknown>
|
|
56
|
+
): Promise<HostMcpCallResult>;
|
|
57
|
+
oneOff(connection: DiscoveredConnection): HostMcpOneOff;
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
/**
|
|
61
|
+
* Model-facing advertised names after {@link sanitizeMcpToolName} — the
|
|
62
|
+
* same MCP-client shape the Cursor-account bridge documents
|
|
63
|
+
* (`^[a-zA-Z0-9_-]{1,128}$`). Authored `agent/tools/` filenames stay on
|
|
64
|
+
* discovery's stricter `NAME_PATTERN` (must start alphanumeric).
|
|
65
|
+
*/
|
|
66
|
+
export const ADVERTISED_TOOL_NAME_PATTERN: RegExp = /^[A-Za-z0-9_-]{1,128}$/;
|
|
67
|
+
|
|
68
|
+
const ANY_OBJECT_SCHEMA: JsonSchemaObject = {
|
|
69
|
+
type: "object",
|
|
70
|
+
additionalProperties: true,
|
|
71
|
+
};
|
|
72
|
+
|
|
73
|
+
/** How one advertising connection is listed and called. */
|
|
74
|
+
export interface AdvertisedToolSource {
|
|
75
|
+
listTools(): Promise<HostMcpToolInfo[]>;
|
|
76
|
+
callTool(
|
|
77
|
+
toolName: string,
|
|
78
|
+
args: Record<string, unknown>
|
|
79
|
+
): Promise<HostMcpCallResult>;
|
|
80
|
+
}
|
|
81
|
+
|
|
82
|
+
/**
|
|
83
|
+
* Resolve the advertised tools for one session. Returns `[]` when no
|
|
84
|
+
* connection advertises; throws (failing the turn) when a listing fails
|
|
85
|
+
* or a definition is invalid.
|
|
86
|
+
*/
|
|
87
|
+
export async function resolveAdvertisedTools(args: {
|
|
88
|
+
agent: ResolvedAgent;
|
|
89
|
+
session: SessionInfo;
|
|
90
|
+
hostMcp: AdvertiseHostMcp;
|
|
91
|
+
/** Test seam; defaults to {@link sourceForConnection}. */
|
|
92
|
+
sourceFor?: (
|
|
93
|
+
connection: DiscoveredConnection,
|
|
94
|
+
session: SessionInfo,
|
|
95
|
+
hostMcp: AdvertiseHostMcp
|
|
96
|
+
) => Promise<AdvertisedToolSource>;
|
|
97
|
+
}): Promise<DiscoveredTool[]> {
|
|
98
|
+
const advertising = args.agent.connections.filter(
|
|
99
|
+
(connection) => connection.advertiseTools === true
|
|
100
|
+
);
|
|
101
|
+
if (advertising.length === 0) {
|
|
102
|
+
return [];
|
|
103
|
+
}
|
|
104
|
+
const sourceFor = args.sourceFor ?? sourceForConnection;
|
|
105
|
+
const claimed = new Set(args.agent.tools.map((tool) => tool.name));
|
|
106
|
+
const resolved: DiscoveredTool[] = [];
|
|
107
|
+
for (const connection of advertising) {
|
|
108
|
+
const source = await sourceFor(connection, args.session, args.hostMcp);
|
|
109
|
+
let listed: HostMcpToolInfo[];
|
|
110
|
+
try {
|
|
111
|
+
listed = await source.listTools();
|
|
112
|
+
} catch (error) {
|
|
113
|
+
throw new Error(
|
|
114
|
+
`Failed to list tools on advertised connection "${connection.name}": ${describeError(error)}`,
|
|
115
|
+
{ cause: error }
|
|
116
|
+
);
|
|
117
|
+
}
|
|
118
|
+
const exposed = exposeListedTools(listed, claimed);
|
|
119
|
+
for (const { info, exposedName } of exposed) {
|
|
120
|
+
resolved.push(toDiscoveredTool(connection, info, exposedName, source));
|
|
121
|
+
claimed.add(exposedName);
|
|
122
|
+
}
|
|
123
|
+
}
|
|
124
|
+
return resolved;
|
|
125
|
+
}
|
|
126
|
+
|
|
127
|
+
/**
|
|
128
|
+
* The production source for one advertising connection: the shared
|
|
129
|
+
* `host.mcp` registry client for auth-less connections (which also covers
|
|
130
|
+
* serve-resolved transports — Cursor account bridges, peers), or a
|
|
131
|
+
* registry one-off with the session's headers substituted when the
|
|
132
|
+
* connection has per-session `auth`. The auth callback is evaluated once
|
|
133
|
+
* per turn, here; the one-off opens a fresh client per operation so one
|
|
134
|
+
* session's identity can never serve another's call.
|
|
135
|
+
*/
|
|
136
|
+
export async function sourceForConnection(
|
|
137
|
+
connection: DiscoveredConnection,
|
|
138
|
+
session: SessionInfo,
|
|
139
|
+
hostMcp: AdvertiseHostMcp
|
|
140
|
+
): Promise<AdvertisedToolSource> {
|
|
141
|
+
if (connection.auth === undefined) {
|
|
142
|
+
return {
|
|
143
|
+
listTools: () => hostMcp.listTools(connection.name),
|
|
144
|
+
callTool: (toolName, callArgs) =>
|
|
145
|
+
hostMcp.callTool(connection.name, toolName, callArgs),
|
|
146
|
+
};
|
|
147
|
+
}
|
|
148
|
+
const transport = connection.transport;
|
|
149
|
+
if (!("url" in transport)) {
|
|
150
|
+
// Discovery rejects auth on non-URL transports; guard for callers that
|
|
151
|
+
// bypass discovery (hand-built projects).
|
|
152
|
+
throw new Error(
|
|
153
|
+
`Connection "${connection.name}" has per-session auth but no URL transport.`
|
|
154
|
+
);
|
|
155
|
+
}
|
|
156
|
+
const evaluated = await connection.auth(session);
|
|
157
|
+
return hostMcp.oneOff({
|
|
158
|
+
...connection,
|
|
159
|
+
transport: {
|
|
160
|
+
...transport,
|
|
161
|
+
headers: { ...transport.headers, ...evaluated.headers },
|
|
162
|
+
},
|
|
163
|
+
});
|
|
164
|
+
}
|
|
165
|
+
|
|
166
|
+
/**
|
|
167
|
+
* Same catalog rule as the Cursor-account bridge: slug illegal characters,
|
|
168
|
+
* then `_2` / `_3` … for colliders (including authored tools already in
|
|
169
|
+
* `claimed`). Suffix assignment is stable for a colliding group: sort by
|
|
170
|
+
* original advertised name, independent of `listTools` order.
|
|
171
|
+
*/
|
|
172
|
+
function exposeListedTools(
|
|
173
|
+
listed: HostMcpToolInfo[],
|
|
174
|
+
claimed: ReadonlySet<string>
|
|
175
|
+
): Array<{ info: HostMcpToolInfo; exposedName: string }> {
|
|
176
|
+
const byBase = new Map<string, HostMcpToolInfo[]>();
|
|
177
|
+
for (const info of listed) {
|
|
178
|
+
const base = sanitizeMcpToolName(info.name);
|
|
179
|
+
const group = byBase.get(base);
|
|
180
|
+
if (group === undefined) {
|
|
181
|
+
byBase.set(base, [info]);
|
|
182
|
+
} else {
|
|
183
|
+
group.push(info);
|
|
184
|
+
}
|
|
185
|
+
}
|
|
186
|
+
const taken = new Set(claimed);
|
|
187
|
+
const exposedNameByInfo = new Map<HostMcpToolInfo, string>();
|
|
188
|
+
const sortedBases = [...byBase.keys()].sort((left, right) =>
|
|
189
|
+
left < right ? -1 : left > right ? 1 : 0
|
|
190
|
+
);
|
|
191
|
+
for (const base of sortedBases) {
|
|
192
|
+
const group = byBase.get(base)!;
|
|
193
|
+
group.sort((left, right) =>
|
|
194
|
+
left.name < right.name ? -1 : left.name > right.name ? 1 : 0
|
|
195
|
+
);
|
|
196
|
+
group.forEach((info, index) => {
|
|
197
|
+
let suffixIndex = index;
|
|
198
|
+
let exposedName = suffixMcpToolName(base, suffixIndex);
|
|
199
|
+
while (taken.has(exposedName)) {
|
|
200
|
+
suffixIndex++;
|
|
201
|
+
exposedName = suffixMcpToolName(base, suffixIndex);
|
|
202
|
+
}
|
|
203
|
+
taken.add(exposedName);
|
|
204
|
+
exposedNameByInfo.set(info, exposedName);
|
|
205
|
+
});
|
|
206
|
+
}
|
|
207
|
+
return listed.map((info) => ({
|
|
208
|
+
info,
|
|
209
|
+
exposedName: exposedNameByInfo.get(info)!,
|
|
210
|
+
}));
|
|
211
|
+
}
|
|
212
|
+
|
|
213
|
+
function toDiscoveredTool(
|
|
214
|
+
connection: DiscoveredConnection,
|
|
215
|
+
info: HostMcpToolInfo,
|
|
216
|
+
exposedName: string,
|
|
217
|
+
source: AdvertisedToolSource
|
|
218
|
+
): DiscoveredTool {
|
|
219
|
+
const description =
|
|
220
|
+
info.description === undefined || info.description.trim() === ""
|
|
221
|
+
? `${info.name} — MCP tool on the "${connection.name}" connection, forwarded 1:1.`
|
|
222
|
+
: info.description;
|
|
223
|
+
const inputSchema = info.inputSchema ?? ANY_OBJECT_SCHEMA;
|
|
224
|
+
const outputSchema = info.outputSchema;
|
|
225
|
+
const definition: ToolDefinition = brandDefinition("tool", {
|
|
226
|
+
description,
|
|
227
|
+
inputSchema,
|
|
228
|
+
...(outputSchema === undefined ? {} : { outputSchema }),
|
|
229
|
+
execute: async (input: Record<string, unknown>) =>
|
|
230
|
+
formatMcpToolResult(
|
|
231
|
+
connection.name,
|
|
232
|
+
info.name,
|
|
233
|
+
await source.callTool(info.name, input ?? {})
|
|
234
|
+
),
|
|
235
|
+
} as unknown as ToolDefinition);
|
|
236
|
+
return {
|
|
237
|
+
name: exposedName,
|
|
238
|
+
description,
|
|
239
|
+
inputSchema,
|
|
240
|
+
...(outputSchema === undefined ? {} : { outputSchema }),
|
|
241
|
+
execution: "server",
|
|
242
|
+
needsApproval: false,
|
|
243
|
+
definition,
|
|
244
|
+
};
|
|
245
|
+
}
|
|
246
|
+
|
|
247
|
+
/**
|
|
248
|
+
* Render an MCP call result for the model: text parts joined, non-text
|
|
249
|
+
* parts noted by type, `isError` surfaced as a thrown error so the turn
|
|
250
|
+
* records a tool error instead of error-shaped prose.
|
|
251
|
+
*/
|
|
252
|
+
export function formatMcpToolResult(
|
|
253
|
+
connectionName: string,
|
|
254
|
+
toolName: string,
|
|
255
|
+
result: HostMcpCallResult
|
|
256
|
+
): string {
|
|
257
|
+
const parts = result.content.map((item) =>
|
|
258
|
+
item.type === "text" && typeof item.text === "string"
|
|
259
|
+
? item.text
|
|
260
|
+
: `[${item.type} content omitted]`
|
|
261
|
+
);
|
|
262
|
+
const text = parts.join("\n").trim();
|
|
263
|
+
if (result.isError === true) {
|
|
264
|
+
throw new Error(
|
|
265
|
+
text === "" ? `${connectionName} tool ${toolName} failed` : text
|
|
266
|
+
);
|
|
267
|
+
}
|
|
268
|
+
if (text !== "") {
|
|
269
|
+
return text;
|
|
270
|
+
}
|
|
271
|
+
return result.structuredContent !== undefined
|
|
272
|
+
? JSON.stringify(result.structuredContent, null, 2)
|
|
273
|
+
: "(empty result)";
|
|
274
|
+
}
|
|
275
|
+
|
|
276
|
+
function describeError(error: unknown): string {
|
|
277
|
+
return error instanceof Error ? error.message : String(error);
|
|
278
|
+
}
|
|
@@ -22,6 +22,7 @@ import {
|
|
|
22
22
|
SIGN_IN_HINT,
|
|
23
23
|
} from "./cursor/credentials.js";
|
|
24
24
|
import { authorizeCursorAccountConnectors } from "./cursor-account-mcp-auth.js";
|
|
25
|
+
import { readDeployTemplate } from "./cursor-agent-template.js";
|
|
25
26
|
import {
|
|
26
27
|
AgentServeDeployClient,
|
|
27
28
|
type DeleteAccepted,
|
|
@@ -661,11 +662,20 @@ async function deployOne(
|
|
|
661
662
|
...(egressAllowedDomains.length === 0 ? {} : { egressAllowedDomains }),
|
|
662
663
|
publicRoutePaths:
|
|
663
664
|
publicRoutePaths.length === 0 ? undefined : publicRoutePaths,
|
|
665
|
+
// Deliberately NO manifest here: the control plane captures it from the
|
|
666
|
+
// provisioned engine (`GET /v1/manifest` after the health probe), which
|
|
667
|
+
// is the single write path for deploy manifests. `july manifest` remains
|
|
668
|
+
// available for local visibility only.
|
|
664
669
|
};
|
|
665
670
|
|
|
666
671
|
let accepted: DeployAccepted;
|
|
667
672
|
try {
|
|
668
|
-
accepted = await ctx.client.deploy({
|
|
673
|
+
accepted = await ctx.client.deploy({
|
|
674
|
+
teamId: ctx.teamId,
|
|
675
|
+
slug,
|
|
676
|
+
source,
|
|
677
|
+
template: readDeployTemplate(dir),
|
|
678
|
+
});
|
|
669
679
|
} catch (error) {
|
|
670
680
|
return renderApiError(error, ctx.err);
|
|
671
681
|
}
|
|
@@ -0,0 +1,63 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* `july manifest` — print the offline deploy manifest (Wd-1 of
|
|
3
|
+
* `docs/agent-serve/agent-sdk-event-ingress-plan.md`).
|
|
4
|
+
*
|
|
5
|
+
* Loads the agent project from disk and emits the statically-derived
|
|
6
|
+
* metadata the control plane stores at deploy time: declared GitHub webhook
|
|
7
|
+
* events, egress domains, public routes, and the full `/v1/info` payload.
|
|
8
|
+
* Runs entirely offline — no VM, no engine, no network.
|
|
9
|
+
*/
|
|
10
|
+
|
|
11
|
+
import {
|
|
12
|
+
buildAgentDeployManifest,
|
|
13
|
+
parseAgentDeployManifest,
|
|
14
|
+
} from "./deploy-manifest.js";
|
|
15
|
+
import { isAgentProjectDir, loadAgentProject } from "./discovery.js";
|
|
16
|
+
|
|
17
|
+
export interface CmdManifestOptions {
|
|
18
|
+
dir: string;
|
|
19
|
+
/** Compact single-line JSON (machine consumption); default pretty. */
|
|
20
|
+
json?: boolean;
|
|
21
|
+
/** Test seams. */
|
|
22
|
+
out?: (line: string) => void;
|
|
23
|
+
err?: (line: string) => void;
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
export async function cmdManifest(
|
|
27
|
+
options: CmdManifestOptions
|
|
28
|
+
): Promise<number> {
|
|
29
|
+
const out = options.out ?? ((line: string) => process.stdout.write(line));
|
|
30
|
+
const err = options.err ?? ((line: string) => process.stderr.write(line));
|
|
31
|
+
|
|
32
|
+
if (!(await isAgentProjectDir(options.dir))) {
|
|
33
|
+
err(
|
|
34
|
+
`No agent project found at ${options.dir} (expected an agent.ts default-exporting defineAgent({ ... })).\n`
|
|
35
|
+
);
|
|
36
|
+
return 1;
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
const project = await loadAgentProject(options.dir);
|
|
40
|
+
for (const diagnostic of project.diagnostics) {
|
|
41
|
+
err(`${diagnostic.severity}: ${diagnostic.message}\n`);
|
|
42
|
+
}
|
|
43
|
+
if (project.diagnostics.some((d) => d.severity === "error")) {
|
|
44
|
+
return 1;
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
const manifest = buildAgentDeployManifest(project);
|
|
48
|
+
// Round-trip through the wire schema so `july manifest` can never emit
|
|
49
|
+
// something the control plane contract would reject.
|
|
50
|
+
if (
|
|
51
|
+
parseAgentDeployManifest(JSON.parse(JSON.stringify(manifest))) === undefined
|
|
52
|
+
) {
|
|
53
|
+
err("internal error: generated manifest failed schema validation\n");
|
|
54
|
+
return 1;
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
out(
|
|
58
|
+
options.json === true
|
|
59
|
+
? `${JSON.stringify(manifest)}\n`
|
|
60
|
+
: `${JSON.stringify(manifest, null, 2)}\n`
|
|
61
|
+
);
|
|
62
|
+
return 0;
|
|
63
|
+
}
|
|
@@ -402,7 +402,16 @@ function writePendingAdminWait(
|
|
|
402
402
|
? poll.oauthAuthorizeUrl
|
|
403
403
|
: undefined;
|
|
404
404
|
ctx.err(`Waiting for a Slack admin to approve the app${appSuffix}.\n\n`);
|
|
405
|
-
if (
|
|
405
|
+
if (poll.approvalRequest === "pending") {
|
|
406
|
+
// Already in the admin queue: nothing to file, so no browser hop.
|
|
407
|
+
ctx.err(
|
|
408
|
+
ctx.dim(` Approval request sent; workspace owners were notified.\n\n`)
|
|
409
|
+
);
|
|
410
|
+
if (requestUrl !== undefined) {
|
|
411
|
+
ctx.err(ctx.dim(` Send a reminder from:\n\n`));
|
|
412
|
+
ctx.err(` ${requestUrl}\n\n`);
|
|
413
|
+
}
|
|
414
|
+
} else if (requestUrl !== undefined) {
|
|
406
415
|
ctx.err(
|
|
407
416
|
ctx.dim(
|
|
408
417
|
` Slack will notify workspace owners once the request is in their queue.\n` +
|
|
@@ -7,6 +7,7 @@
|
|
|
7
7
|
*/
|
|
8
8
|
|
|
9
9
|
import { CLI_COMMAND_NAME, PACKAGE_NAME } from "../distribution.js";
|
|
10
|
+
import { MEMORY_TS } from "../init-scaffold.js";
|
|
10
11
|
import { pascalCase, SlugRegistry, slugify } from "./slug.js";
|
|
11
12
|
import type {
|
|
12
13
|
ActionJson,
|
|
@@ -128,7 +129,7 @@ export function convertWorkflow(
|
|
|
128
129
|
hasSlackAction && emitSlackAccountConnection(automation, out);
|
|
129
130
|
|
|
130
131
|
if (workflow.memoryEnabled === true) {
|
|
131
|
-
out.files.push({ path: "agent/hooks/memory.ts", contents:
|
|
132
|
+
out.files.push({ path: "agent/hooks/memory.ts", contents: MEMORY_TS });
|
|
132
133
|
}
|
|
133
134
|
|
|
134
135
|
out.setupSteps.push(
|
|
@@ -1410,13 +1411,3 @@ function jsonComment(value: unknown): string[] {
|
|
|
1410
1411
|
function dedupe(values: string[]): string[] {
|
|
1411
1412
|
return [...new Set(values)];
|
|
1412
1413
|
}
|
|
1413
|
-
|
|
1414
|
-
/** Memory hook contents — identical to the `initProject` scaffold. */
|
|
1415
|
-
const MEMORY_HOOK = `// Journals every turn (timestamp, session, user message, result) so
|
|
1416
|
-
// future sessions can recall past work. The journal is shared across every
|
|
1417
|
-
// session — and every user — of this agent. Pass your own MemoryBackend to
|
|
1418
|
-
// change where memories live, or delete this file to opt out.
|
|
1419
|
-
import { memoryHook } from "${PACKAGE_NAME}/memory";
|
|
1420
|
-
|
|
1421
|
-
export default memoryHook();
|
|
1422
|
-
`;
|