@cursor/july 0.1.40 → 0.1.42
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 +13 -6
- package/dist/bin/agent-serve.js +28 -9
- package/dist/channels/slack/attachments.d.ts +82 -0
- package/dist/channels/slack/attachments.d.ts.map +1 -0
- package/dist/channels/slack/attachments.js +520 -0
- package/dist/channels/slack/cursor-account.d.ts +7 -1
- package/dist/channels/slack/cursor-account.d.ts.map +1 -1
- package/dist/channels/slack/cursor-account.js +2 -2
- package/dist/channels/slack/dispatch.d.ts +4 -3
- package/dist/channels/slack/dispatch.d.ts.map +1 -1
- package/dist/channels/slack/dispatch.js +84 -21
- package/dist/channels/slack/inbound.d.ts +6 -0
- package/dist/channels/slack/inbound.d.ts.map +1 -1
- package/dist/channels/slack/inbound.js +48 -2
- package/dist/channels/slack/index.d.ts +1 -0
- package/dist/channels/slack/index.d.ts.map +1 -1
- package/dist/channels/slack/index.js +1 -0
- package/dist/channels/slack/manifest.d.ts.map +1 -1
- package/dist/channels/slack/manifest.js +1 -0
- package/dist/channels/slack/slack-channel.d.ts.map +1 -1
- package/dist/channels/slack/slack-channel.js +7 -4
- package/dist/channels/slack/types.d.ts +49 -1
- package/dist/channels/slack/types.d.ts.map +1 -1
- package/dist/docs/404.html +2 -2
- package/dist/docs/ab.html +6 -6
- package/dist/docs/assets/{ab.md.6cLOW7--.js → ab.md.hdxsvX5M.js} +2 -2
- package/dist/docs/assets/{app.DpGLSiym.js → app.C4-Gwi7g.js} +1 -1
- package/dist/docs/assets/{building-with-agents.md.txrcGU2B.js → building-with-agents.md.PeZaZA1P.js} +1 -1
- package/dist/docs/assets/chunks/@localSearchIndexroot.BlU3A8EB.js +1 -0
- package/dist/docs/assets/chunks/{VPLocalSearchBox.B11XEMST.js → VPLocalSearchBox.DDoLm843.js} +1 -1
- package/dist/docs/assets/chunks/{theme.iTidHsAx.js → theme.SbjGIiM0.js} +2 -2
- package/dist/docs/assets/{deployment.md.CuK5SNjN.js → deployment.md.BHVjVqRa.js} +4 -4
- package/dist/docs/assets/{deployment.md.CuK5SNjN.lean.js → deployment.md.BHVjVqRa.lean.js} +1 -1
- package/dist/docs/assets/{evals.md.BQXI3rXy.js → evals.md.qeoGgPw0.js} +3 -3
- package/dist/docs/assets/example-agents_index.md.xmJ87d_3.js +2 -0
- package/dist/docs/assets/{guides_webhooks.md.BERuBSJW.js → guides_webhooks.md.DB-r_er9.js} +47 -4
- package/dist/docs/assets/{guides_webhooks.md.BERuBSJW.lean.js → guides_webhooks.md.DB-r_er9.lean.js} +1 -1
- package/dist/docs/assets/index.md.BKpbkCa6.js +24 -0
- package/dist/docs/assets/{index.md.CmhptOmN.lean.js → index.md.BKpbkCa6.lean.js} +1 -1
- package/dist/docs/assets/{quickstart.md.C_b6ESpD.js → quickstart.md.rIbfahJM.js} +4 -4
- package/dist/docs/assets/{reference_cli.md.Byvrg8eu.js → reference_cli.md.DqEqQpGn.js} +5 -5
- package/dist/docs/assets/{reference_cli.md.Byvrg8eu.lean.js → reference_cli.md.DqEqQpGn.lean.js} +1 -1
- package/dist/docs/assets/reference_hooks.md.B40QAG6m.js +14 -0
- package/dist/docs/assets/{reference_hooks.md.BGDw4VLm.lean.js → reference_hooks.md.B40QAG6m.lean.js} +1 -1
- package/dist/docs/assets/{storage.md.mQDtIULc.js → storage.md.DcGSnIxX.js} +10 -4
- package/dist/docs/assets/{storage.md.mQDtIULc.lean.js → storage.md.DcGSnIxX.lean.js} +1 -1
- package/dist/docs/assets/troubleshooting.md.CkgwmVI0.js +1 -0
- package/dist/docs/assets/{troubleshooting.md.B5RVX_tL.lean.js → troubleshooting.md.CkgwmVI0.lean.js} +1 -1
- package/dist/docs/building-with-agents.html +5 -5
- package/dist/docs/concepts.html +3 -3
- package/dist/docs/deployment.html +6 -6
- package/dist/docs/evals.html +7 -7
- 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 +5 -5
- 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/github.html +3 -3
- package/dist/docs/guides/human-in-the-loop.html +3 -3
- package/dist/docs/guides/mcp-oauth.html +3 -3
- package/dist/docs/guides/slack.html +3 -3
- package/dist/docs/guides/webhooks.html +49 -6
- package/dist/docs/hashmap.json +1 -1
- package/dist/docs/hillclimbing.html +3 -3
- package/dist/docs/index.html +7 -7
- package/dist/docs/quickstart.html +8 -8
- package/dist/docs/reference/agent-config.html +3 -3
- package/dist/docs/reference/artifacts.html +3 -3
- package/dist/docs/reference/channels.html +3 -3
- package/dist/docs/reference/cli.html +8 -8
- package/dist/docs/reference/connections.html +3 -3
- package/dist/docs/reference/hooks.html +9 -7
- 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 +3 -3
- package/dist/docs/reference/skills.html +3 -3
- package/dist/docs/reference/subagents.html +3 -3
- package/dist/docs/reference/tools.html +3 -3
- package/dist/docs/scaffolding-agents.html +3 -3
- package/dist/docs/storage.html +14 -8
- package/dist/docs/troubleshooting.html +5 -5
- package/dist/hooks.d.ts +3 -1
- package/dist/hooks.d.ts.map +1 -1
- package/dist/hooks.js +3 -1
- package/dist/index.d.ts +4 -2
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +3 -1
- package/dist/internal/cli-ax.d.ts.map +1 -1
- package/dist/internal/cli-ax.js +22 -2
- package/dist/internal/cli-deploy.d.ts +6 -0
- package/dist/internal/cli-deploy.d.ts.map +1 -1
- package/dist/internal/cli-deploy.js +14 -4
- package/dist/internal/cli-mcp.js +4 -4
- package/dist/internal/deploy-client.js +1 -1
- package/dist/internal/discovery.d.ts.map +1 -1
- package/dist/internal/discovery.js +35 -7
- package/dist/internal/distribution.d.ts.map +1 -1
- package/dist/internal/distribution.js +3 -1
- package/dist/internal/durable-session-store.d.ts +48 -0
- package/dist/internal/durable-session-store.d.ts.map +1 -0
- package/dist/internal/durable-session-store.js +86 -0
- package/dist/internal/hosting.d.ts +1 -1
- package/dist/internal/hosting.js +2 -2
- package/dist/internal/init-project.d.ts +34 -0
- package/dist/internal/init-project.d.ts.map +1 -1
- package/dist/internal/init-project.js +121 -2
- package/dist/internal/ledger-serving.d.ts +101 -0
- package/dist/internal/ledger-serving.d.ts.map +1 -0
- package/dist/internal/ledger-serving.js +174 -0
- package/dist/internal/listen-port.d.ts +22 -0
- package/dist/internal/listen-port.d.ts.map +1 -0
- package/dist/internal/listen-port.js +77 -0
- package/dist/internal/playground/static.d.ts +21 -4
- package/dist/internal/playground/static.d.ts.map +1 -1
- package/dist/internal/playground/static.js +82 -18
- package/dist/internal/sdk-runner.d.ts.map +1 -1
- package/dist/internal/sdk-runner.js +10 -1
- package/dist/internal/server.d.ts.map +1 -1
- package/dist/internal/server.js +61 -47
- package/dist/internal/session-engine.d.ts +57 -1
- package/dist/internal/session-engine.d.ts.map +1 -1
- package/dist/internal/session-engine.js +118 -28
- package/dist/internal/slack-provision-client.js +1 -1
- package/dist/internal/workspace.d.ts +6 -2
- package/dist/internal/workspace.d.ts.map +1 -1
- package/dist/internal/workspace.js +10 -2
- package/dist/kv/memory-kv.d.ts +23 -0
- package/dist/kv/memory-kv.d.ts.map +1 -0
- package/dist/kv/memory-kv.js +103 -0
- package/dist/kv.d.ts +22 -0
- package/dist/kv.d.ts.map +1 -0
- package/dist/kv.js +20 -0
- package/dist/ledger/session-ledger.d.ts +204 -0
- package/dist/ledger/session-ledger.d.ts.map +1 -0
- package/dist/ledger/session-ledger.js +382 -0
- package/dist/ledger.d.ts +11 -0
- package/dist/ledger.d.ts.map +1 -0
- package/dist/ledger.js +9 -0
- package/dist/playground/assets/index-B3HBneZZ.js +85 -0
- package/dist/playground/assets/index-Bqk9nplh.css +1 -0
- package/dist/playground/index.html +2 -2
- package/dist/storage-backends/cursor-hosted.d.ts +25 -3
- package/dist/storage-backends/cursor-hosted.d.ts.map +1 -1
- package/dist/storage-backends/cursor-hosted.js +50 -2
- package/dist/storage-backends/file-kv.d.ts +5 -2
- package/dist/storage-backends/file-kv.d.ts.map +1 -1
- package/dist/storage-backends/file-kv.js +107 -7
- package/dist/storage.d.ts +60 -5
- package/dist/storage.d.ts.map +1 -1
- package/dist/storage.js +28 -4
- package/dist/types.d.ts +132 -6
- package/dist/types.d.ts.map +1 -1
- package/dist/types.js +14 -0
- package/docs/README.md +10 -7
- package/docs/ab.md +2 -2
- package/docs/building-with-agents.md +1 -1
- package/docs/deployment.md +34 -11
- package/docs/evals.md +3 -3
- package/docs/example-agents/index.md +1 -1
- package/docs/guides/webhooks.md +87 -0
- package/docs/quickstart.md +7 -8
- package/docs/reference/cli.md +15 -6
- package/docs/reference/hooks.md +12 -3
- package/docs/storage.md +67 -7
- package/docs/troubleshooting.md +10 -2
- package/package.json +20 -7
- package/skills/create-agent/SKILL.md +1 -1
- package/skills/debug/SKILL.md +4 -0
- package/src/bin/agent-serve.ts +27 -11
- package/src/channels/slack/attachments.ts +635 -0
- package/src/channels/slack/cursor-account.ts +8 -0
- package/src/channels/slack/dispatch.ts +121 -6
- package/src/channels/slack/inbound.ts +60 -0
- package/src/channels/slack/index.ts +1 -0
- package/src/channels/slack/manifest.ts +1 -0
- package/src/channels/slack/slack-channel.ts +7 -0
- package/src/channels/slack/types.ts +47 -1
- package/src/hooks.ts +3 -1
- package/src/index.ts +9 -0
- package/src/internal/cli-ax.ts +25 -1
- package/src/internal/cli-deploy.ts +22 -4
- package/src/internal/cli-mcp.ts +4 -4
- package/src/internal/deploy-client.ts +1 -1
- package/src/internal/discovery.ts +42 -5
- package/src/internal/distribution.ts +3 -1
- package/src/internal/durable-session-store.ts +95 -0
- package/src/internal/hosting.ts +2 -2
- package/src/internal/init-project.ts +151 -2
- package/src/internal/ledger-serving.ts +240 -0
- package/src/internal/listen-port.ts +85 -0
- package/src/internal/playground/static.ts +111 -20
- package/src/internal/sdk-runner.ts +11 -1
- package/src/internal/server.ts +68 -61
- package/src/internal/session-engine.ts +193 -16
- package/src/internal/slack-provision-client.ts +1 -1
- package/src/internal/workspace.ts +14 -3
- package/src/kv/memory-kv.ts +99 -0
- package/src/kv.ts +27 -0
- package/src/ledger/session-ledger.ts +535 -0
- package/src/ledger.ts +29 -0
- package/src/storage-backends/cursor-hosted.ts +108 -3
- package/src/storage-backends/file-kv.ts +128 -12
- package/src/storage.ts +90 -6
- package/src/types.ts +139 -7
- package/dist/channels/slack/post-update-delivery.d.ts +0 -85
- package/dist/channels/slack/post-update-delivery.d.ts.map +0 -1
- package/dist/docs/assets/chunks/@localSearchIndexroot.D82_RVtF.js +0 -1
- package/dist/docs/assets/example-agents_index.md.DgGBwckv.js +0 -2
- package/dist/docs/assets/index.md.CmhptOmN.js +0 -24
- package/dist/docs/assets/reference_hooks.md.BGDw4VLm.js +0 -12
- package/dist/docs/assets/troubleshooting.md.B5RVX_tL.js +0 -1
- package/dist/internal/json-dir-store.d.ts +0 -32
- package/dist/internal/json-dir-store.d.ts.map +0 -1
- package/dist/internal/persistence-coordinator.d.ts +0 -127
- package/dist/internal/persistence-coordinator.d.ts.map +0 -1
- package/dist/multi-tenant.d.ts +0 -80
- package/dist/multi-tenant.d.ts.map +0 -1
- package/dist/multi-tenant.js +0 -69
- package/dist/persistence.d.ts +0 -184
- package/dist/persistence.d.ts.map +0 -1
- package/dist/playground/assets/index-BRhBbnd4.css +0 -1
- package/dist/playground/assets/index-Bc1oFgFG.js +0 -85
- package/dist/storage-backends/postgres-kv.d.ts +0 -82
- package/dist/storage-backends/postgres-kv.d.ts.map +0 -1
- package/dist/storage-backends/postgres-kv.js +0 -185
- package/src/storage-backends/postgres-kv.ts +0 -253
- /package/dist/docs/assets/{ab.md.6cLOW7--.lean.js → ab.md.hdxsvX5M.lean.js} +0 -0
- /package/dist/docs/assets/{building-with-agents.md.txrcGU2B.lean.js → building-with-agents.md.PeZaZA1P.lean.js} +0 -0
- /package/dist/docs/assets/{evals.md.BQXI3rXy.lean.js → evals.md.qeoGgPw0.lean.js} +0 -0
- /package/dist/docs/assets/{example-agents_index.md.DgGBwckv.lean.js → example-agents_index.md.xmJ87d_3.lean.js} +0 -0
- /package/dist/docs/assets/{quickstart.md.C_b6ESpD.lean.js → quickstart.md.rIbfahJM.lean.js} +0 -0
|
@@ -0,0 +1,85 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Bind an HTTP server to a port, with a clear next-port path when 3000 (or
|
|
3
|
+
* whatever was requested) is already taken — a common onboarding failure.
|
|
4
|
+
*/
|
|
5
|
+
|
|
6
|
+
import { once } from "node:events";
|
|
7
|
+
import type { Server } from "node:http";
|
|
8
|
+
import { CLI_COMMAND_NAME } from "./distribution.js";
|
|
9
|
+
|
|
10
|
+
/** Default listen port for `serve` / `dev` when `--port` is omitted. */
|
|
11
|
+
export const DEFAULT_SERVE_PORT = 3000;
|
|
12
|
+
|
|
13
|
+
/** How many ports above the default to try when the default is taken. */
|
|
14
|
+
const DEFAULT_PORT_FALLBACK_SPAN = 20;
|
|
15
|
+
|
|
16
|
+
export function isAddrInUse(error: unknown): boolean {
|
|
17
|
+
return (
|
|
18
|
+
typeof error === "object" &&
|
|
19
|
+
error !== null &&
|
|
20
|
+
"code" in error &&
|
|
21
|
+
(error as { code?: unknown }).code === "EADDRINUSE"
|
|
22
|
+
);
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
export function formatPortInUseHint(port: number): string {
|
|
26
|
+
const next = port === 0 ? 3001 : port + 1;
|
|
27
|
+
return (
|
|
28
|
+
`port ${port} is already in use. ` +
|
|
29
|
+
`Try \`${CLI_COMMAND_NAME} dev --port ${next}\` or \`--port 0\` for any free port.`
|
|
30
|
+
);
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
/**
|
|
34
|
+
* `server.listen` with fallback when the caller used the default port.
|
|
35
|
+
* Explicit `--port N` (including `0`) fails immediately with a next-port hint.
|
|
36
|
+
*/
|
|
37
|
+
export async function listenHttpServer(args: {
|
|
38
|
+
server: Server;
|
|
39
|
+
host: string;
|
|
40
|
+
port: number;
|
|
41
|
+
/** True when the caller passed `port` (including 0); skip fallback. */
|
|
42
|
+
portWasExplicit: boolean;
|
|
43
|
+
logger: (line: string) => void;
|
|
44
|
+
}): Promise<number> {
|
|
45
|
+
const { server, host, logger } = args;
|
|
46
|
+
const startPort = args.port;
|
|
47
|
+
if (args.portWasExplicit || startPort === 0) {
|
|
48
|
+
try {
|
|
49
|
+
server.listen(startPort, host);
|
|
50
|
+
await once(server, "listening");
|
|
51
|
+
} catch (error) {
|
|
52
|
+
if (isAddrInUse(error)) {
|
|
53
|
+
throw new Error(formatPortInUseHint(startPort));
|
|
54
|
+
}
|
|
55
|
+
throw error;
|
|
56
|
+
}
|
|
57
|
+
const address = server.address();
|
|
58
|
+
if (address === null || typeof address === "string") {
|
|
59
|
+
throw new Error("server listening without an address");
|
|
60
|
+
}
|
|
61
|
+
return address.port;
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
const last = startPort + DEFAULT_PORT_FALLBACK_SPAN;
|
|
65
|
+
for (let port = startPort; port <= last; port++) {
|
|
66
|
+
try {
|
|
67
|
+
server.listen(port, host);
|
|
68
|
+
await once(server, "listening");
|
|
69
|
+
if (port !== startPort) {
|
|
70
|
+
logger(
|
|
71
|
+
`[agent-sdk] port ${startPort} in use; listening on ${port} instead (pass --port to pick)`
|
|
72
|
+
);
|
|
73
|
+
}
|
|
74
|
+
return port;
|
|
75
|
+
} catch (error) {
|
|
76
|
+
if (!isAddrInUse(error)) {
|
|
77
|
+
throw error;
|
|
78
|
+
}
|
|
79
|
+
if (port === last) {
|
|
80
|
+
throw new Error(formatPortInUseHint(port));
|
|
81
|
+
}
|
|
82
|
+
}
|
|
83
|
+
}
|
|
84
|
+
throw new Error(formatPortInUseHint(last));
|
|
85
|
+
}
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
/**
|
|
2
|
-
* Serves the built Vite playground SPA and the
|
|
2
|
+
* Serves the built Vite playground SPA and the host home page.
|
|
3
3
|
*
|
|
4
4
|
* The playground is a Vite + React app (see `playground/`). `serve` auto-builds
|
|
5
5
|
* `dist/playground/` when the local vite toolchain is present (see
|
|
@@ -93,33 +93,111 @@ export function renderPlaygroundAsset(file: string): Response {
|
|
|
93
93
|
});
|
|
94
94
|
}
|
|
95
95
|
|
|
96
|
-
/**
|
|
96
|
+
/** Slack surface summary for the host home / `GET /v1/agents`. */
|
|
97
|
+
export type AgentIndexSlack =
|
|
98
|
+
| { kind: "cursor-account"; handle: string }
|
|
99
|
+
| { kind: "socket" };
|
|
100
|
+
|
|
101
|
+
/** One row on the host home page and `GET /v1/agents`. */
|
|
97
102
|
export interface AgentIndexEntry {
|
|
98
103
|
slug: string;
|
|
99
104
|
name: string;
|
|
100
105
|
model: string;
|
|
101
106
|
tools: number;
|
|
102
107
|
channels: number;
|
|
108
|
+
slack?: AgentIndexSlack;
|
|
109
|
+
}
|
|
110
|
+
|
|
111
|
+
export interface HostHomeOptions {
|
|
112
|
+
/** When false, omit `/docs` from the route list. Default true. */
|
|
113
|
+
docs?: boolean;
|
|
114
|
+
/** Same as the serve host's `multi` — mounts `/v1/agents` + host `/v1/health`. */
|
|
115
|
+
multi?: boolean;
|
|
103
116
|
}
|
|
104
117
|
|
|
105
|
-
/**
|
|
106
|
-
|
|
118
|
+
/**
|
|
119
|
+
* Orienting `/` page: mounted agents (playground links) plus live host routes.
|
|
120
|
+
* Used for both single-agent (empty slug) and multi-agent mounts.
|
|
121
|
+
*/
|
|
122
|
+
export function renderAgentsIndexHtml(
|
|
123
|
+
agents: AgentIndexEntry[],
|
|
124
|
+
options: HostHomeOptions = {}
|
|
125
|
+
): string {
|
|
126
|
+
const docs = options.docs !== false;
|
|
127
|
+
const multi = options.multi === true;
|
|
107
128
|
const cards = agents
|
|
108
129
|
.map((agent) => {
|
|
130
|
+
const playground =
|
|
131
|
+
agent.slug === "" ? "/playground" : `/${agent.slug}/playground`;
|
|
132
|
+
const slugLabel = agent.slug === "" ? "/" : `/${agent.slug}`;
|
|
109
133
|
const meta = `${agent.model || "—"} · ${agent.tools} tool${
|
|
110
134
|
agent.tools === 1 ? "" : "s"
|
|
111
135
|
} · ${agent.channels} channel${agent.channels === 1 ? "" : "s"}`;
|
|
112
|
-
return ` <a class="card" href="
|
|
136
|
+
return ` <a class="card" href="${escapeHtml(playground)}">
|
|
113
137
|
<div class="card-name">${escapeHtml(agent.name)}</div>
|
|
114
|
-
<div class="card-slug"
|
|
138
|
+
<div class="card-slug">${escapeHtml(slugLabel)} → playground</div>
|
|
115
139
|
<div class="card-meta">${escapeHtml(meta)}</div>
|
|
116
140
|
</a>`;
|
|
117
141
|
})
|
|
118
142
|
.join("\n");
|
|
119
|
-
|
|
143
|
+
|
|
144
|
+
const routes = hostRouteRows(agents, docs, multi)
|
|
145
|
+
.map(
|
|
146
|
+
(row) =>
|
|
147
|
+
` <tr><td><a href="${escapeHtml(row.href)}"><code>${escapeHtml(row.path)}</code></a></td><td>${escapeHtml(row.blurb)}</td></tr>`
|
|
148
|
+
)
|
|
149
|
+
.join("\n");
|
|
150
|
+
|
|
151
|
+
return HOST_HOME_TEMPLATE.replace(
|
|
120
152
|
"<!--CARDS-->",
|
|
121
153
|
cards || ' <div class="card-meta">No agents mounted.</div>'
|
|
122
|
-
)
|
|
154
|
+
)
|
|
155
|
+
.replace("<!--COUNT-->", String(agents.length))
|
|
156
|
+
.replace("<!--ROUTES-->", routes);
|
|
157
|
+
}
|
|
158
|
+
|
|
159
|
+
function hostRouteRows(
|
|
160
|
+
agents: AgentIndexEntry[],
|
|
161
|
+
docs: boolean,
|
|
162
|
+
multi: boolean
|
|
163
|
+
): Array<{ path: string; href: string; blurb: string }> {
|
|
164
|
+
const rows: Array<{ path: string; href: string; blurb: string }> = [
|
|
165
|
+
{ path: "/", href: "/", blurb: "This page" },
|
|
166
|
+
];
|
|
167
|
+
for (const agent of agents) {
|
|
168
|
+
const base = agent.slug === "" ? "" : `/${agent.slug}`;
|
|
169
|
+
const label = agent.slug === "" ? agent.name : agent.slug;
|
|
170
|
+
rows.push({
|
|
171
|
+
path: `${base}/playground`,
|
|
172
|
+
href: `${base}/playground`,
|
|
173
|
+
blurb: `Playground — ${label}`,
|
|
174
|
+
});
|
|
175
|
+
rows.push({
|
|
176
|
+
path: `${base}/v1/health`,
|
|
177
|
+
href: `${base}/v1/health`,
|
|
178
|
+
blurb: `Health — ${label}`,
|
|
179
|
+
});
|
|
180
|
+
}
|
|
181
|
+
if (multi) {
|
|
182
|
+
rows.push({
|
|
183
|
+
path: "/v1/agents",
|
|
184
|
+
href: "/v1/agents",
|
|
185
|
+
blurb: "JSON index of mounted agents",
|
|
186
|
+
});
|
|
187
|
+
rows.push({
|
|
188
|
+
path: "/v1/health",
|
|
189
|
+
href: "/v1/health",
|
|
190
|
+
blurb: "Host liveness",
|
|
191
|
+
});
|
|
192
|
+
}
|
|
193
|
+
if (docs) {
|
|
194
|
+
rows.push({
|
|
195
|
+
path: "/docs",
|
|
196
|
+
href: "/docs/",
|
|
197
|
+
blurb: "Agent SDK documentation",
|
|
198
|
+
});
|
|
199
|
+
}
|
|
200
|
+
return rows;
|
|
123
201
|
}
|
|
124
202
|
|
|
125
203
|
function escapeHtml(value: string): string {
|
|
@@ -137,7 +215,7 @@ function fallbackHtml(baseHref: string): string {
|
|
|
137
215
|
<base href="${escapeHtml(baseHref)}" />
|
|
138
216
|
<meta charset="utf-8" />
|
|
139
217
|
<meta name="viewport" content="width=device-width, initial-scale=1" />
|
|
140
|
-
<title>agent-
|
|
218
|
+
<title>agent-sdk playground</title>
|
|
141
219
|
<style>
|
|
142
220
|
body { margin: 0; background: #0e1116; color: #e6edf3; font: 14px/1.6 ui-sans-serif, system-ui, sans-serif; }
|
|
143
221
|
.box { max-width: 640px; margin: 64px auto; padding: 0 24px; }
|
|
@@ -150,7 +228,7 @@ function fallbackHtml(baseHref: string): string {
|
|
|
150
228
|
<div class="box">
|
|
151
229
|
<h1>Playground bundle not built</h1>
|
|
152
230
|
<p>
|
|
153
|
-
The Vite playground has not been built yet. <code>agent-
|
|
231
|
+
The Vite playground has not been built yet. <code>agent-sdk serve</code>
|
|
154
232
|
auto-builds it when the local vite toolchain is available; otherwise run
|
|
155
233
|
<code>pnpm run build:playground</code> from <code>packages/agent-serve</code>,
|
|
156
234
|
or <code>pnpm run dev:playground</code> for Vite HMR.
|
|
@@ -160,33 +238,46 @@ function fallbackHtml(baseHref: string): string {
|
|
|
160
238
|
</html>`;
|
|
161
239
|
}
|
|
162
240
|
|
|
163
|
-
const
|
|
241
|
+
const HOST_HOME_TEMPLATE = `<!doctype html>
|
|
164
242
|
<html lang="en">
|
|
165
243
|
<head>
|
|
166
244
|
<meta charset="utf-8" />
|
|
167
245
|
<meta name="viewport" content="width=device-width, initial-scale=1" />
|
|
168
|
-
<title>
|
|
246
|
+
<title>Agent SDK</title>
|
|
169
247
|
<style>
|
|
170
248
|
:root { color-scheme: dark; }
|
|
171
249
|
body { margin: 0; background: #0e1116; color: #e6edf3; font: 14px/1.6 ui-sans-serif, system-ui, -apple-system, sans-serif; }
|
|
172
|
-
.
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
.
|
|
250
|
+
.wrap { max-width: 880px; margin: 0 auto; padding: 48px 24px; }
|
|
251
|
+
h1 { font-size: 20px; font-weight: 650; margin: 0 0 2px; }
|
|
252
|
+
h2 { font-size: 13px; font-weight: 600; text-transform: uppercase; letter-spacing: 0.04em; color: #8b949e; margin: 36px 0 12px; }
|
|
253
|
+
.sub { color: #8b949e; font-size: 13px; margin-bottom: 28px; }
|
|
254
|
+
.grid { display: grid; grid-template-columns: repeat(auto-fill, minmax(240px, 1fr)); gap: 14px; }
|
|
176
255
|
.card { display: block; text-decoration: none; color: inherit; background: #161b22; border: 1px solid #30363d; border-radius: 12px; padding: 16px 18px; transition: border-color 0.12s; }
|
|
177
256
|
.card:hover { border-color: #6cb6ff; }
|
|
178
257
|
.card-name { font-size: 15px; font-weight: 600; }
|
|
179
258
|
.card-slug { font-family: ui-monospace, monospace; font-size: 12px; color: #6cb6ff; margin-top: 2px; }
|
|
180
259
|
.card-meta { color: #6e7681; font-size: 12px; margin-top: 10px; }
|
|
260
|
+
table.routes { width: 100%; border-collapse: collapse; font-size: 13px; }
|
|
261
|
+
table.routes td { padding: 8px 0; border-bottom: 1px solid #21262d; vertical-align: top; }
|
|
262
|
+
table.routes td:first-child { width: 42%; padding-right: 16px; }
|
|
263
|
+
table.routes code { font-family: ui-monospace, monospace; font-size: 12px; color: #6cb6ff; }
|
|
264
|
+
table.routes a { text-decoration: none; }
|
|
265
|
+
table.routes a:hover code { text-decoration: underline; }
|
|
266
|
+
.muted { color: #8b949e; }
|
|
181
267
|
</style>
|
|
182
268
|
</head>
|
|
183
269
|
<body>
|
|
184
|
-
<div class="
|
|
185
|
-
<h1>
|
|
186
|
-
<div class="sub"><!--COUNT-->
|
|
187
|
-
<
|
|
270
|
+
<div class="wrap">
|
|
271
|
+
<h1>Agent SDK</h1>
|
|
272
|
+
<div class="sub"><!--COUNT--> agent(s) on this host. Open a playground or use a route below.</div>
|
|
273
|
+
<h2>Agents</h2>
|
|
274
|
+
<div class="grid">
|
|
188
275
|
<!--CARDS-->
|
|
189
276
|
</div>
|
|
277
|
+
<h2>Routes</h2>
|
|
278
|
+
<table class="routes">
|
|
279
|
+
<!--ROUTES-->
|
|
280
|
+
</table>
|
|
190
281
|
</div>
|
|
191
282
|
</body>
|
|
192
283
|
</html>`;
|
|
@@ -171,7 +171,17 @@ export class CursorSdkRunner implements AgentRunner {
|
|
|
171
171
|
const agentPromise = this.getAgent(request);
|
|
172
172
|
try {
|
|
173
173
|
const agent = await agentPromise;
|
|
174
|
-
const
|
|
174
|
+
const sendMessage =
|
|
175
|
+
request.images !== undefined && request.images.length > 0
|
|
176
|
+
? {
|
|
177
|
+
text: request.prompt,
|
|
178
|
+
images: request.images.map((image) => ({
|
|
179
|
+
data: image.data,
|
|
180
|
+
mimeType: image.mimeType,
|
|
181
|
+
})),
|
|
182
|
+
}
|
|
183
|
+
: request.prompt;
|
|
184
|
+
const run = await agent.send(sendMessage, {
|
|
175
185
|
onDelta: async ({ update }) => {
|
|
176
186
|
try {
|
|
177
187
|
await request.onUpdate(update);
|
package/src/internal/server.ts
CHANGED
|
@@ -99,6 +99,7 @@ import {
|
|
|
99
99
|
requireSessionOwner,
|
|
100
100
|
} from "./http-channel.js";
|
|
101
101
|
import { validateToolInput } from "./json-schema.js";
|
|
102
|
+
import { DEFAULT_SERVE_PORT, listenHttpServer } from "./listen-port.js";
|
|
102
103
|
import {
|
|
103
104
|
createLocalControlPlane,
|
|
104
105
|
type LocalControlPlane,
|
|
@@ -592,52 +593,26 @@ export async function startServer(
|
|
|
592
593
|
})),
|
|
593
594
|
}),
|
|
594
595
|
});
|
|
596
|
+
}
|
|
595
597
|
|
|
596
|
-
|
|
597
|
-
|
|
598
|
-
|
|
599
|
-
|
|
600
|
-
|
|
601
|
-
|
|
602
|
-
|
|
603
|
-
|
|
604
|
-
|
|
605
|
-
|
|
606
|
-
|
|
607
|
-
|
|
608
|
-
|
|
609
|
-
|
|
610
|
-
|
|
611
|
-
|
|
612
|
-
|
|
613
|
-
|
|
614
|
-
handle: `@Cursor ${cursorName}`,
|
|
615
|
-
}
|
|
616
|
-
: hasSocketSlack
|
|
617
|
-
? { kind: "socket" as const }
|
|
618
|
-
: undefined;
|
|
619
|
-
return {
|
|
620
|
-
slug,
|
|
621
|
-
name: project.name,
|
|
622
|
-
model:
|
|
623
|
-
typeof project.agent.model === "string"
|
|
624
|
-
? project.agent.model
|
|
625
|
-
: (project.agent.model?.id ?? ""),
|
|
626
|
-
tools: project.agent.tools.length,
|
|
627
|
-
channels: project.channels.length + 1,
|
|
628
|
-
...(slack !== undefined ? { slack } : {}),
|
|
629
|
-
};
|
|
630
|
-
});
|
|
631
|
-
const indexHtml = renderAgentsIndexHtml(entries);
|
|
632
|
-
router.add({
|
|
633
|
-
method: "GET",
|
|
634
|
-
pattern: "/",
|
|
635
|
-
auth: "none",
|
|
636
|
-
handler: () =>
|
|
637
|
-
new Response(indexHtml, {
|
|
638
|
-
headers: { "content-type": "text/html; charset=utf-8" },
|
|
639
|
-
}),
|
|
640
|
-
});
|
|
598
|
+
// Orienting `/` for every layout (single empty-slug and multi).
|
|
599
|
+
// Lists playground links plus live routes (playground, health, docs).
|
|
600
|
+
if (playground) {
|
|
601
|
+
const entries = buildAgentIndexEntries(runtimes);
|
|
602
|
+
const indexHtml = renderAgentsIndexHtml(entries, {
|
|
603
|
+
docs: docsSite,
|
|
604
|
+
multi,
|
|
605
|
+
});
|
|
606
|
+
router.add({
|
|
607
|
+
method: "GET",
|
|
608
|
+
pattern: "/",
|
|
609
|
+
auth: "none",
|
|
610
|
+
handler: () =>
|
|
611
|
+
new Response(indexHtml, {
|
|
612
|
+
headers: { "content-type": "text/html; charset=utf-8" },
|
|
613
|
+
}),
|
|
614
|
+
});
|
|
615
|
+
if (multi) {
|
|
641
616
|
router.add({
|
|
642
617
|
method: "GET",
|
|
643
618
|
pattern: "/v1/agents",
|
|
@@ -725,10 +700,17 @@ export async function startServer(
|
|
|
725
700
|
});
|
|
726
701
|
|
|
727
702
|
const host = options.host ?? "127.0.0.1";
|
|
728
|
-
const
|
|
703
|
+
const portWasExplicit = options.port !== undefined;
|
|
704
|
+
const requestedPort = options.port ?? DEFAULT_SERVE_PORT;
|
|
705
|
+
let boundPort: number;
|
|
729
706
|
try {
|
|
730
|
-
|
|
731
|
-
|
|
707
|
+
boundPort = await listenHttpServer({
|
|
708
|
+
server,
|
|
709
|
+
host,
|
|
710
|
+
port: requestedPort,
|
|
711
|
+
portWasExplicit,
|
|
712
|
+
logger,
|
|
713
|
+
});
|
|
732
714
|
} catch (error) {
|
|
733
715
|
await cursorEventRelay?.stop();
|
|
734
716
|
await cursorSlackRelay?.stop();
|
|
@@ -737,7 +719,7 @@ export async function startServer(
|
|
|
737
719
|
}
|
|
738
720
|
const address = server.address() as AddressInfo;
|
|
739
721
|
const displayHost = host === "0.0.0.0" || host === "::" ? "127.0.0.1" : host;
|
|
740
|
-
const url = `http://${displayHost}:${
|
|
722
|
+
const url = `http://${displayHost}:${boundPort}`;
|
|
741
723
|
|
|
742
724
|
// Resolve peer + Cursor account MCP connections now that the listen port is
|
|
743
725
|
// known (see resolved-connections.ts for the URL/runtime rules).
|
|
@@ -1303,18 +1285,6 @@ function mountAgentRoutes(
|
|
|
1303
1285
|
auth: "none",
|
|
1304
1286
|
handler: (_request, ctx) => renderPlaygroundAsset(ctx.params.file ?? ""),
|
|
1305
1287
|
});
|
|
1306
|
-
if (!multi) {
|
|
1307
|
-
router.add({
|
|
1308
|
-
method: "GET",
|
|
1309
|
-
pattern: "/",
|
|
1310
|
-
auth: "none",
|
|
1311
|
-
handler: () =>
|
|
1312
|
-
new Response(null, {
|
|
1313
|
-
status: 302,
|
|
1314
|
-
headers: { location: "/playground" },
|
|
1315
|
-
}),
|
|
1316
|
-
});
|
|
1317
|
-
}
|
|
1318
1288
|
}
|
|
1319
1289
|
|
|
1320
1290
|
for (const route of buildHttpChannelRoutes({
|
|
@@ -1900,6 +1870,43 @@ function slackAgentNameFromSlug(slug: string): string {
|
|
|
1900
1870
|
* resolved. Duplicate names are a startup error — the backend routes
|
|
1901
1871
|
* `@Cursor <name> …` by name, so two mounts cannot share one.
|
|
1902
1872
|
*/
|
|
1873
|
+
function buildAgentIndexEntries(runtimes: MountedRuntime[]): AgentIndexEntry[] {
|
|
1874
|
+
const cursorSlackBySlug = new Map(
|
|
1875
|
+
collectCursorSlackTargets(runtimes).map((target) => [
|
|
1876
|
+
target.runtime.slug,
|
|
1877
|
+
target.agentName,
|
|
1878
|
+
])
|
|
1879
|
+
);
|
|
1880
|
+
return runtimes.map(({ slug, project }) => {
|
|
1881
|
+
const cursorName = cursorSlackBySlug.get(slug);
|
|
1882
|
+
const hasSocketSlack = project.channels.some(
|
|
1883
|
+
(channel) =>
|
|
1884
|
+
channel.definition.meta?.kind === "slack" &&
|
|
1885
|
+
channel.definition.meta?.slackCursorAccount !== true
|
|
1886
|
+
);
|
|
1887
|
+
const slack =
|
|
1888
|
+
cursorName !== undefined
|
|
1889
|
+
? {
|
|
1890
|
+
kind: "cursor-account" as const,
|
|
1891
|
+
handle: `@Cursor ${cursorName}`,
|
|
1892
|
+
}
|
|
1893
|
+
: hasSocketSlack
|
|
1894
|
+
? { kind: "socket" as const }
|
|
1895
|
+
: undefined;
|
|
1896
|
+
return {
|
|
1897
|
+
slug,
|
|
1898
|
+
name: project.name,
|
|
1899
|
+
model:
|
|
1900
|
+
typeof project.agent.model === "string"
|
|
1901
|
+
? project.agent.model
|
|
1902
|
+
: (project.agent.model?.id ?? ""),
|
|
1903
|
+
tools: project.agent.tools.length,
|
|
1904
|
+
channels: project.channels.length + 1,
|
|
1905
|
+
slack,
|
|
1906
|
+
};
|
|
1907
|
+
});
|
|
1908
|
+
}
|
|
1909
|
+
|
|
1903
1910
|
function collectCursorSlackTargets(
|
|
1904
1911
|
runtimes: MountedRuntime[]
|
|
1905
1912
|
): CursorSlackTarget[] {
|