@cursor/july 0.1.16 → 0.1.18
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/README.md +9 -4
- package/dist/bin/agent-serve.js +60 -2
- package/dist/channels/slack/api.d.ts.map +1 -1
- package/dist/channels/slack/api.js +13 -3
- package/dist/channels/slack/auth.d.ts +7 -1
- package/dist/channels/slack/auth.d.ts.map +1 -1
- package/dist/channels/slack/auth.js +14 -0
- package/dist/channels/slack/blocks.d.ts +61 -0
- package/dist/channels/slack/blocks.d.ts.map +1 -0
- package/dist/channels/slack/blocks.js +90 -0
- package/dist/channels/slack/cursor-account.d.ts.map +1 -1
- package/dist/channels/slack/cursor-account.js +1 -1
- package/dist/channels/slack/defaults.d.ts +2 -0
- package/dist/channels/slack/defaults.d.ts.map +1 -1
- package/dist/channels/slack/defaults.js +29 -3
- package/dist/channels/slack/dispatch.d.ts +3 -17
- package/dist/channels/slack/dispatch.d.ts.map +1 -1
- package/dist/channels/slack/dispatch.js +4 -1
- package/dist/channels/slack/inbound.d.ts.map +1 -1
- package/dist/channels/slack/inbound.js +6 -1
- package/dist/channels/slack/index.d.ts +2 -0
- package/dist/channels/slack/index.d.ts.map +1 -1
- package/dist/channels/slack/index.js +2 -0
- package/dist/channels/slack/init.d.ts.map +1 -1
- package/dist/channels/slack/init.js +4 -1
- package/dist/channels/slack/interactive.d.ts +39 -3
- package/dist/channels/slack/interactive.d.ts.map +1 -1
- package/dist/channels/slack/interactive.js +153 -7
- package/dist/channels/slack/manifest.d.ts +13 -0
- package/dist/channels/slack/manifest.d.ts.map +1 -1
- package/dist/channels/slack/manifest.js +36 -14
- package/dist/channels/slack/message-body.d.ts +13 -0
- package/dist/channels/slack/message-body.d.ts.map +1 -0
- package/dist/channels/slack/message-body.js +82 -0
- package/dist/channels/slack/setup.d.ts +4 -1
- package/dist/channels/slack/setup.d.ts.map +1 -1
- package/dist/channels/slack/setup.js +16 -2
- package/dist/channels/slack/slack-channel.d.ts.map +1 -1
- package/dist/channels/slack/slack-channel.js +24 -3
- package/dist/channels/slack/thread-context.d.ts +0 -2
- package/dist/channels/slack/thread-context.d.ts.map +1 -1
- package/dist/channels/slack/thread-context.js +1 -65
- package/dist/channels/slack/types.d.ts +93 -1
- package/dist/channels/slack/types.d.ts.map +1 -1
- package/dist/connections.d.ts +4 -1
- package/dist/connections.d.ts.map +1 -1
- package/dist/connections.js +4 -1
- package/dist/docs/404.html +2 -2
- package/dist/docs/ab.html +3 -3
- package/dist/docs/assets/{app.DjHC-Ggf.js → app.BR5EdVSq.js} +1 -1
- package/dist/docs/assets/chunks/@localSearchIndexroot.BOzkeUi8.js +1 -0
- package/dist/docs/assets/chunks/{VPLocalSearchBox.DwviwmIq.js → VPLocalSearchBox.CNCzfUKC.js} +1 -1
- package/dist/docs/assets/chunks/{theme.BIpeYSon.js → theme.CwKvMSWv.js} +2 -2
- package/dist/docs/assets/{example-agents_security-reviewer.md.BZSNycMf.js → example-agents_security-reviewer.md.Dhj_m7_B.js} +1 -1
- package/dist/docs/assets/{guides_mcp-oauth.md.DqmEOQY1.js → guides_mcp-oauth.md.Dd8EgSem.js} +3 -2
- package/dist/docs/assets/{guides_mcp-oauth.md.DqmEOQY1.lean.js → guides_mcp-oauth.md.Dd8EgSem.lean.js} +1 -1
- package/dist/docs/assets/{guides_slack.md.FWale6Ip.js → guides_slack.md.D_xFKlnF.js} +1 -1
- package/dist/docs/assets/{reference_connections.md.CsSr3rDz.js → reference_connections.md.B9Q3TOve.js} +12 -5
- package/dist/docs/assets/{reference_connections.md.CsSr3rDz.lean.js → reference_connections.md.B9Q3TOve.lean.js} +1 -1
- package/dist/docs/building-with-agents.html +3 -3
- package/dist/docs/concepts.html +3 -3
- 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 +5 -5
- 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 +6 -5
- package/dist/docs/guides/slack.html +5 -5
- 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 +3 -3
- package/dist/docs/reference/channels.html +3 -3
- package/dist/docs/reference/cli.html +3 -3
- package/dist/docs/reference/connections.html +14 -7
- 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 +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 +3 -3
- package/dist/docs/troubleshooting.html +3 -3
- package/dist/evals/assertions.d.ts +190 -0
- package/dist/evals/assertions.d.ts.map +1 -0
- package/dist/evals/assertions.js +461 -0
- package/dist/evals/expect.d.ts +95 -0
- package/dist/evals/expect.d.ts.map +1 -0
- package/dist/evals/expect.js +194 -0
- package/dist/evals/judge.d.ts +133 -0
- package/dist/evals/judge.d.ts.map +1 -0
- package/dist/evals/judge.js +228 -0
- package/dist/evals/loaders.d.ts +51 -0
- package/dist/evals/loaders.d.ts.map +1 -0
- package/dist/evals/loaders.js +124 -0
- package/dist/evals/matchers.d.ts +95 -0
- package/dist/evals/matchers.d.ts.map +1 -0
- package/dist/evals/matchers.js +145 -0
- package/dist/evals/reporters.d.ts +70 -0
- package/dist/evals/reporters.d.ts.map +1 -0
- package/dist/evals/reporters.js +221 -0
- package/dist/evals/results.d.ts +103 -0
- package/dist/evals/results.d.ts.map +1 -0
- package/dist/evals/results.js +28 -0
- package/dist/evals/run-facts.d.ts +77 -0
- package/dist/evals/run-facts.d.ts.map +1 -0
- package/dist/evals/run-facts.js +187 -0
- package/dist/evals.d.ts +118 -31
- package/dist/evals.d.ts.map +1 -1
- package/dist/evals.js +46 -12
- package/dist/index.d.ts +1 -1
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +1 -1
- package/dist/internal/builtin-tools/index.d.ts +10 -0
- package/dist/internal/builtin-tools/index.d.ts.map +1 -0
- package/dist/internal/builtin-tools/index.js +27 -0
- package/dist/internal/builtin-tools/reminders.d.ts +9 -0
- package/dist/internal/builtin-tools/reminders.d.ts.map +1 -0
- package/dist/internal/builtin-tools/reminders.js +138 -0
- package/dist/internal/cli-ax.d.ts +27 -0
- package/dist/internal/cli-ax.d.ts.map +1 -1
- package/dist/internal/cli-ax.js +90 -12
- package/dist/internal/cli-mcp.d.ts +8 -0
- package/dist/internal/cli-mcp.d.ts.map +1 -1
- package/dist/internal/cli-mcp.js +98 -0
- package/dist/internal/cli-slack.d.ts +29 -1
- package/dist/internal/cli-slack.d.ts.map +1 -1
- package/dist/internal/cli-slack.js +799 -13
- package/dist/internal/cursor-event-relay.d.ts +30 -0
- package/dist/internal/cursor-event-relay.d.ts.map +1 -1
- package/dist/internal/cursor-event-relay.js +37 -0
- package/dist/internal/deploy-client.d.ts +7 -0
- package/dist/internal/deploy-client.d.ts.map +1 -1
- package/dist/internal/deploy-client.js +9 -0
- package/dist/internal/discovery.d.ts.map +1 -1
- package/dist/internal/discovery.js +70 -9
- package/dist/internal/distribution.d.ts.map +1 -1
- package/dist/internal/distribution.js +2 -0
- package/dist/internal/eval-judge-model.d.ts +59 -0
- package/dist/internal/eval-judge-model.d.ts.map +1 -0
- package/dist/internal/eval-judge-model.js +131 -0
- package/dist/internal/eval-run-store.d.ts.map +1 -1
- package/dist/internal/eval-run-store.js +12 -20
- package/dist/internal/eval-runner.d.ts +31 -25
- package/dist/internal/eval-runner.d.ts.map +1 -1
- package/dist/internal/eval-runner.js +329 -126
- package/dist/internal/evals-client.d.ts.map +1 -1
- package/dist/internal/evals-client.js +4 -1
- package/dist/internal/local-env.d.ts +8 -0
- package/dist/internal/local-env.d.ts.map +1 -0
- package/dist/internal/local-env.js +47 -0
- package/dist/internal/playground/static.d.ts +3 -0
- package/dist/internal/playground/static.d.ts.map +1 -1
- package/dist/internal/playground/static.js +3 -0
- package/dist/internal/reminder-runner.d.ts +7 -0
- package/dist/internal/reminder-runner.d.ts.map +1 -1
- package/dist/internal/reminder-runner.js +21 -0
- package/dist/internal/run-client.d.ts +15 -0
- package/dist/internal/run-client.d.ts.map +1 -1
- package/dist/internal/run-client.js +3 -2
- package/dist/internal/sdk-runner.d.ts +51 -1
- package/dist/internal/sdk-runner.d.ts.map +1 -1
- package/dist/internal/sdk-runner.js +176 -36
- package/dist/internal/server.d.ts.map +1 -1
- package/dist/internal/server.js +11 -1
- package/dist/internal/session-engine.d.ts +18 -5
- package/dist/internal/session-engine.d.ts.map +1 -1
- package/dist/internal/session-engine.js +81 -19
- package/dist/internal/slack-provision-client.d.ts +133 -0
- package/dist/internal/slack-provision-client.d.ts.map +1 -0
- package/dist/internal/slack-provision-client.js +286 -0
- package/dist/playground/assets/cursor-icons-16-f_W_ogc-.woff2 +0 -0
- package/dist/playground/assets/index-DRjS5klQ.js +85 -0
- package/dist/playground/assets/index-TCDs-UhZ.css +1 -0
- package/dist/playground/index.html +2 -2
- package/dist/types.d.ts +98 -4
- package/dist/types.d.ts.map +1 -1
- package/dist/types.js +26 -0
- package/docs/example-agents/security-reviewer.md +1 -1
- package/docs/guides/mcp-oauth.md +10 -5
- package/docs/guides/slack.md +3 -2
- package/docs/reference/connections.md +28 -18
- package/package.json +20 -2
- package/skills/create-agent/SKILL.md +15 -7
- package/skills/debug/SKILL.md +3 -1
- package/skills/mcp-auth/SKILL.md +1 -1
- package/skills/setup-slack/SKILL.md +177 -11
- package/src/bin/agent-serve.ts +63 -2
- package/src/channels/slack/api.ts +16 -3
- package/src/channels/slack/auth.ts +16 -1
- package/src/channels/slack/blocks.ts +139 -0
- package/src/channels/slack/cursor-account.ts +1 -0
- package/src/channels/slack/defaults.ts +32 -4
- package/src/channels/slack/dispatch.ts +6 -19
- package/src/channels/slack/inbound.ts +6 -1
- package/src/channels/slack/index.ts +2 -0
- package/src/channels/slack/init.ts +3 -0
- package/src/channels/slack/interactive.ts +184 -19
- package/src/channels/slack/manifest.ts +37 -6
- package/src/channels/slack/message-body.ts +90 -0
- package/src/channels/slack/setup.ts +16 -2
- package/src/channels/slack/slack-channel.ts +37 -6
- package/src/channels/slack/thread-context.ts +1 -69
- package/src/channels/slack/types.ts +105 -1
- package/src/connections.ts +4 -1
- package/src/evals/assertions.ts +704 -0
- package/src/evals/expect.ts +272 -0
- package/src/evals/judge.ts +346 -0
- package/src/evals/loaders.ts +113 -0
- package/src/evals/matchers.ts +246 -0
- package/src/evals/reporters.ts +274 -0
- package/src/evals/results.ts +132 -0
- package/src/evals/run-facts.ts +274 -0
- package/src/evals.ts +205 -42
- package/src/index.ts +2 -0
- package/src/internal/builtin-tools/index.ts +40 -0
- package/src/internal/builtin-tools/reminders.ts +158 -0
- package/src/internal/cli-ax.ts +134 -15
- package/src/internal/cli-mcp.ts +118 -5
- package/src/internal/cli-slack.ts +1017 -15
- package/src/internal/cursor-event-relay.ts +67 -0
- package/src/internal/deploy-client.ts +10 -0
- package/src/internal/discovery.ts +83 -5
- package/src/internal/distribution.ts +2 -0
- package/src/internal/eval-judge-model.ts +148 -0
- package/src/internal/eval-run-store.ts +10 -14
- package/src/internal/eval-runner.ts +460 -214
- package/src/internal/evals-client.ts +5 -0
- package/src/internal/local-env.ts +53 -0
- package/src/internal/playground/static.ts +3 -0
- package/src/internal/reminder-runner.ts +30 -0
- package/src/internal/run-client.ts +17 -1
- package/src/internal/sdk-runner.ts +234 -35
- package/src/internal/server.ts +12 -0
- package/src/internal/session-engine.ts +103 -21
- package/src/internal/slack-provision-client.ts +442 -0
- package/src/types.ts +125 -4
- 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.DZtu0ZIc.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/persistence.d.ts +0 -184
- package/dist/persistence.d.ts.map +0 -1
- package/dist/playground/assets/cursor-icons-16-CQ50JpfO.woff2 +0 -0
- package/dist/playground/assets/index-Bwl4Onx4.js +0 -85
- package/dist/playground/assets/index-ByV4nfch.css +0 -1
- /package/dist/docs/assets/{example-agents_security-reviewer.md.BZSNycMf.lean.js → example-agents_security-reviewer.md.Dhj_m7_B.lean.js} +0 -0
- /package/dist/docs/assets/{guides_slack.md.FWale6Ip.lean.js → guides_slack.md.D_xFKlnF.lean.js} +0 -0
package/src/internal/cli-ax.ts
CHANGED
|
@@ -10,7 +10,13 @@
|
|
|
10
10
|
import { mkdir, mkdtemp, writeFile } from "node:fs/promises";
|
|
11
11
|
import { tmpdir } from "node:os";
|
|
12
12
|
import { join, resolve } from "node:path";
|
|
13
|
-
import
|
|
13
|
+
import { Artifacts, JUnit } from "../evals/reporters.js";
|
|
14
|
+
import type {
|
|
15
|
+
EvalAssertionResult,
|
|
16
|
+
EvalReporter,
|
|
17
|
+
EvalRunSnapshot,
|
|
18
|
+
EvalVerdict,
|
|
19
|
+
} from "../evals.js";
|
|
14
20
|
import { serve } from "../index.js";
|
|
15
21
|
import type { AgentServeHandle } from "../types.js";
|
|
16
22
|
import { lookupSessionContinuation, runChat } from "./chat-client.js";
|
|
@@ -96,6 +102,19 @@ export interface AxCliOptions {
|
|
|
96
102
|
tags?: string[];
|
|
97
103
|
/** Eval ids / path prefixes. */
|
|
98
104
|
evalIds?: string[];
|
|
105
|
+
/** `eval`: a soft threshold miss (`scored`) also fails the exit code. */
|
|
106
|
+
strict?: boolean;
|
|
107
|
+
/** `eval`: write JUnit XML to this path. */
|
|
108
|
+
junit?: string;
|
|
109
|
+
/**
|
|
110
|
+
* `eval`: run-artifact directory. Defaults to a timestamped directory under
|
|
111
|
+
* `<dir>/.agent-serve/evals/`; `false` disables artifacts entirely.
|
|
112
|
+
*/
|
|
113
|
+
artifacts?: string | false;
|
|
114
|
+
/** `eval`: skip reporters declared in `evals.config.ts` and eval files. */
|
|
115
|
+
skipReport?: boolean;
|
|
116
|
+
/** `eval`: override `evals.config.ts` `maxConcurrency`. */
|
|
117
|
+
maxConcurrency?: number;
|
|
99
118
|
/** Scaffold target directory for `init`. */
|
|
100
119
|
initTarget?: string;
|
|
101
120
|
/** Tool name for `call`. */
|
|
@@ -839,6 +858,7 @@ export async function cmdEval(options: AxCliOptions): Promise<number> {
|
|
|
839
858
|
// batch lands in playground history and defineStorage evals (when set).
|
|
840
859
|
if (mode === "local") {
|
|
841
860
|
const progress = stream ? createStreamProgress() : undefined;
|
|
861
|
+
const artifactsDir = resolveEvalArtifactsDir(projectRoot, options);
|
|
842
862
|
try {
|
|
843
863
|
const results = await runDiscoveredEvals({
|
|
844
864
|
projectRoot,
|
|
@@ -846,6 +866,11 @@ export async function cmdEval(options: AxCliOptions): Promise<number> {
|
|
|
846
866
|
filterIds,
|
|
847
867
|
tags,
|
|
848
868
|
timeoutMs: options.timeoutMs,
|
|
869
|
+
maxConcurrency: options.maxConcurrency,
|
|
870
|
+
strict: options.strict === true,
|
|
871
|
+
skipReport: options.skipReport === true,
|
|
872
|
+
reporters: buildCliEvalReporters(options, artifactsDir),
|
|
873
|
+
target: { baseUrl: target.agentUrl, mode: "local" },
|
|
849
874
|
bearerToken: options.bearerToken,
|
|
850
875
|
headers: target.headers,
|
|
851
876
|
verbose: Boolean(options.verbose) || stream,
|
|
@@ -856,7 +881,7 @@ export async function cmdEval(options: AxCliOptions): Promise<number> {
|
|
|
856
881
|
process.stderr.write("No matching evals found.\n");
|
|
857
882
|
return 2;
|
|
858
883
|
}
|
|
859
|
-
return printEvalResults(results, options);
|
|
884
|
+
return printEvalResults(results, options, undefined, artifactsDir);
|
|
860
885
|
} finally {
|
|
861
886
|
progress?.close();
|
|
862
887
|
}
|
|
@@ -1359,6 +1384,53 @@ function createRemoteEvalProgress(
|
|
|
1359
1384
|
};
|
|
1360
1385
|
}
|
|
1361
1386
|
|
|
1387
|
+
/**
|
|
1388
|
+
* Where a local run writes its artifacts.
|
|
1389
|
+
*
|
|
1390
|
+
* Defaults to a timestamped directory under the project's gitignored
|
|
1391
|
+
* `.agent-serve/evals/`, so the full story of a failure is always on disk
|
|
1392
|
+
* without the eval author opting in. `--no-artifacts` turns it off.
|
|
1393
|
+
*/
|
|
1394
|
+
export function resolveEvalArtifactsDir(
|
|
1395
|
+
projectRoot: string,
|
|
1396
|
+
options: Pick<AxCliOptions, "artifacts">
|
|
1397
|
+
): string | undefined {
|
|
1398
|
+
if (options.artifacts === false) {
|
|
1399
|
+
return undefined;
|
|
1400
|
+
}
|
|
1401
|
+
if (typeof options.artifacts === "string" && options.artifacts !== "") {
|
|
1402
|
+
return resolve(options.artifacts);
|
|
1403
|
+
}
|
|
1404
|
+
const stamp = new Date().toISOString().replace(/[:.]/g, "-");
|
|
1405
|
+
return join(projectRoot, ".agent-serve", "evals", stamp);
|
|
1406
|
+
}
|
|
1407
|
+
|
|
1408
|
+
/** JUnit / artifacts reporters requested via CLI flags. */
|
|
1409
|
+
function buildCliEvalReporters(
|
|
1410
|
+
options: AxCliOptions,
|
|
1411
|
+
artifactsDir: string | undefined
|
|
1412
|
+
): EvalReporter[] {
|
|
1413
|
+
const reporters: EvalReporter[] = [];
|
|
1414
|
+
if (artifactsDir !== undefined) {
|
|
1415
|
+
reporters.push(Artifacts({ dir: artifactsDir }));
|
|
1416
|
+
}
|
|
1417
|
+
if (options.junit !== undefined && options.junit !== "") {
|
|
1418
|
+
reporters.push(JUnit({ filePath: options.junit }));
|
|
1419
|
+
}
|
|
1420
|
+
return reporters;
|
|
1421
|
+
}
|
|
1422
|
+
|
|
1423
|
+
function evalVerdictOf(result: EvalRunResult): EvalVerdict {
|
|
1424
|
+
return result.verdict ?? (result.ok ? "passed" : "failed");
|
|
1425
|
+
}
|
|
1426
|
+
|
|
1427
|
+
const EVAL_VERDICT_LABEL: Record<EvalVerdict, string> = {
|
|
1428
|
+
passed: "PASS",
|
|
1429
|
+
failed: "FAIL",
|
|
1430
|
+
scored: "SCORED",
|
|
1431
|
+
skipped: "SKIP",
|
|
1432
|
+
};
|
|
1433
|
+
|
|
1362
1434
|
function printEvalResults(
|
|
1363
1435
|
results: EvalRunResult[],
|
|
1364
1436
|
options: AxCliOptions,
|
|
@@ -1366,12 +1438,17 @@ function printEvalResults(
|
|
|
1366
1438
|
runId?: string;
|
|
1367
1439
|
status?: EvalRunSnapshot["status"];
|
|
1368
1440
|
error?: string;
|
|
1369
|
-
}
|
|
1441
|
+
},
|
|
1442
|
+
artifactsDir?: string
|
|
1370
1443
|
): number {
|
|
1371
|
-
const
|
|
1372
|
-
const
|
|
1444
|
+
const strict = options.strict === true;
|
|
1445
|
+
const counts = { passed: 0, failed: 0, scored: 0, skipped: 0 };
|
|
1446
|
+
for (const result of results) {
|
|
1447
|
+
counts[evalVerdictOf(result)]++;
|
|
1448
|
+
}
|
|
1373
1449
|
const batchFailed = batch?.status === "failed";
|
|
1374
|
-
const ok =
|
|
1450
|
+
const ok =
|
|
1451
|
+
counts.failed === 0 && !(strict && counts.scored > 0) && !batchFailed;
|
|
1375
1452
|
|
|
1376
1453
|
if (batch?.error !== undefined && batch.error !== "" && !options.json) {
|
|
1377
1454
|
// Always surface harness-level failures (not only --verbose).
|
|
@@ -1383,9 +1460,13 @@ function printEvalResults(
|
|
|
1383
1460
|
JSON.stringify(
|
|
1384
1461
|
{
|
|
1385
1462
|
ok,
|
|
1386
|
-
passed,
|
|
1387
|
-
failed,
|
|
1463
|
+
passed: counts.passed,
|
|
1464
|
+
failed: counts.failed,
|
|
1465
|
+
scored: counts.scored,
|
|
1466
|
+
skipped: counts.skipped,
|
|
1467
|
+
strict,
|
|
1388
1468
|
results,
|
|
1469
|
+
...(artifactsDir === undefined ? {} : { artifactsDir }),
|
|
1389
1470
|
...(batch?.runId === undefined ? {} : { runId: batch.runId }),
|
|
1390
1471
|
...(batch?.status === undefined ? {} : { status: batch.status }),
|
|
1391
1472
|
...(batch?.error === undefined || batch.error === ""
|
|
@@ -1398,19 +1479,19 @@ function printEvalResults(
|
|
|
1398
1479
|
);
|
|
1399
1480
|
} else {
|
|
1400
1481
|
for (const r of results) {
|
|
1482
|
+
const verdict = evalVerdictOf(r);
|
|
1401
1483
|
process.stdout.write(
|
|
1402
|
-
`${
|
|
1484
|
+
`${EVAL_VERDICT_LABEL[verdict]} ${r.id} (${(r.durationMs / 1000).toFixed(1)}s)`
|
|
1403
1485
|
);
|
|
1404
1486
|
if (r.description !== undefined) {
|
|
1405
1487
|
process.stdout.write(` — ${r.description}`);
|
|
1406
1488
|
}
|
|
1407
1489
|
process.stdout.write("\n");
|
|
1490
|
+
if (r.skipReason !== undefined) {
|
|
1491
|
+
process.stdout.write(` skipped: ${r.skipReason}\n`);
|
|
1492
|
+
}
|
|
1408
1493
|
for (const a of r.assertions) {
|
|
1409
|
-
process.stdout.write(
|
|
1410
|
-
` ${a.passed ? "✓" : "✗"} ${a.name}${
|
|
1411
|
-
a.detail !== undefined ? ` (${a.detail})` : ""
|
|
1412
|
-
}\n`
|
|
1413
|
-
);
|
|
1494
|
+
process.stdout.write(` ${formatEvalAssertionLine(a)}\n`);
|
|
1414
1495
|
}
|
|
1415
1496
|
for (const [name, value] of Object.entries(r.metrics ?? {})) {
|
|
1416
1497
|
process.stdout.write(` metric ${name}=${String(value)}\n`);
|
|
@@ -1427,13 +1508,51 @@ function printEvalResults(
|
|
|
1427
1508
|
);
|
|
1428
1509
|
}
|
|
1429
1510
|
}
|
|
1511
|
+
const extra: string[] = [];
|
|
1512
|
+
if (counts.scored > 0) {
|
|
1513
|
+
extra.push(
|
|
1514
|
+
`${counts.scored} scored${strict ? " (fatal: --strict)" : ""}`
|
|
1515
|
+
);
|
|
1516
|
+
}
|
|
1517
|
+
if (counts.skipped > 0) {
|
|
1518
|
+
extra.push(`${counts.skipped} skipped`);
|
|
1519
|
+
}
|
|
1430
1520
|
process.stdout.write(
|
|
1431
|
-
`\n${passed} passed, ${failed} failed
|
|
1521
|
+
`\n${counts.passed} passed, ${counts.failed} failed${
|
|
1522
|
+
extra.length === 0 ? "" : `, ${extra.join(", ")}`
|
|
1523
|
+
}, ${results.length} total\n`
|
|
1432
1524
|
);
|
|
1525
|
+
if (artifactsDir !== undefined) {
|
|
1526
|
+
process.stdout.write(`artifacts: ${artifactsDir}\n`);
|
|
1527
|
+
}
|
|
1433
1528
|
}
|
|
1434
1529
|
return ok ? 0 : 1;
|
|
1435
1530
|
}
|
|
1436
1531
|
|
|
1532
|
+
/**
|
|
1533
|
+
* One assertion line. Soft assertions read `~` rather than `✗` when they miss,
|
|
1534
|
+
* so a tracked score is visibly different from a failed gate.
|
|
1535
|
+
*/
|
|
1536
|
+
export function formatEvalAssertionLine(
|
|
1537
|
+
assertion: EvalAssertionResult
|
|
1538
|
+
): string {
|
|
1539
|
+
const soft = (assertion.severity ?? "gate") === "soft";
|
|
1540
|
+
const mark = assertion.passed ? "✓" : soft ? "~" : "✗";
|
|
1541
|
+
const parts: string[] = [];
|
|
1542
|
+
if (assertion.score !== undefined) {
|
|
1543
|
+
parts.push(
|
|
1544
|
+
`score=${assertion.score.toFixed(3)}${
|
|
1545
|
+
assertion.threshold === undefined ? "" : ` >= ${assertion.threshold}`
|
|
1546
|
+
}`
|
|
1547
|
+
);
|
|
1548
|
+
}
|
|
1549
|
+
if (assertion.detail !== undefined) {
|
|
1550
|
+
parts.push(assertion.detail);
|
|
1551
|
+
}
|
|
1552
|
+
const suffix = parts.length === 0 ? "" : ` (${parts.join(", ")})`;
|
|
1553
|
+
return `${mark} ${assertion.name}${soft ? " [soft]" : ""}${suffix}`;
|
|
1554
|
+
}
|
|
1555
|
+
|
|
1437
1556
|
/**
|
|
1438
1557
|
* `logs` — follow deploy progress (`--prod`) then runtime agent logs.
|
|
1439
1558
|
* Local / `--url` tails `/v1/logs` only.
|
package/src/internal/cli-mcp.ts
CHANGED
|
@@ -29,6 +29,8 @@
|
|
|
29
29
|
import { mkdir, readFile, writeFile } from "node:fs/promises";
|
|
30
30
|
import { homedir } from "node:os";
|
|
31
31
|
import { dirname, join } from "node:path";
|
|
32
|
+
import { resolveDeployAuth } from "./cli-deploy.js";
|
|
33
|
+
import { DeployApiError } from "./deploy-client.js";
|
|
32
34
|
import { CLI_COMMAND_NAME as CLI, LOG_PREFIX } from "./distribution.js";
|
|
33
35
|
import {
|
|
34
36
|
ProdTargetError,
|
|
@@ -77,9 +79,16 @@ export interface McpCliOptions {
|
|
|
77
79
|
print?: boolean;
|
|
78
80
|
/** `install`: machine-readable output. */
|
|
79
81
|
json?: boolean;
|
|
82
|
+
/**
|
|
83
|
+
* `install --prod`: write a REMOTE HTTP entry pointing at the stable Cursor
|
|
84
|
+
* MCP gateway (`<api>/…/mcp/<team>/<slug>`) instead of the local stdio
|
|
85
|
+
* proxy. For remote-only MCP hosts (Glass) that cannot spawn stdio.
|
|
86
|
+
*/
|
|
87
|
+
remote?: boolean;
|
|
80
88
|
/** Injected seams for tests. */
|
|
81
89
|
fetchImpl?: typeof fetch;
|
|
82
90
|
resolveProdTargetImpl?: typeof resolveProdTarget;
|
|
91
|
+
resolveDeployAuthImpl?: typeof resolveDeployAuth;
|
|
83
92
|
stdin?: NodeJS.ReadableStream;
|
|
84
93
|
stdout?: { write(chunk: string): unknown };
|
|
85
94
|
err?: (text: string) => void;
|
|
@@ -490,10 +499,9 @@ function requestIdsOf(line: string): Array<string | number> {
|
|
|
490
499
|
// install: write the entry into ~/.cursor/mcp.json
|
|
491
500
|
// ============================================================================
|
|
492
501
|
|
|
493
|
-
|
|
494
|
-
command: string;
|
|
495
|
-
|
|
496
|
-
}
|
|
502
|
+
type McpJsonEntry =
|
|
503
|
+
| { command: string; args: string[] }
|
|
504
|
+
| { url: string; headers?: Record<string, string> };
|
|
497
505
|
|
|
498
506
|
export async function cmdMcpInstall(options: McpCliOptions): Promise<number> {
|
|
499
507
|
const err = options.err ?? defaultErr;
|
|
@@ -502,9 +510,16 @@ export async function cmdMcpInstall(options: McpCliOptions): Promise<number> {
|
|
|
502
510
|
err("--prod and --url are mutually exclusive\n");
|
|
503
511
|
return 1;
|
|
504
512
|
}
|
|
513
|
+
if (options.remote === true) {
|
|
514
|
+
if (options.prod !== true) {
|
|
515
|
+
err("--remote requires --prod (the hosted deployment MCP gateway)\n");
|
|
516
|
+
return 1;
|
|
517
|
+
}
|
|
518
|
+
return cmdMcpInstallRemote(options);
|
|
519
|
+
}
|
|
505
520
|
|
|
506
521
|
let name: string;
|
|
507
|
-
let entry:
|
|
522
|
+
let entry: { command: string; args: string[] };
|
|
508
523
|
if (options.prod === true) {
|
|
509
524
|
let slug: string;
|
|
510
525
|
try {
|
|
@@ -598,6 +613,104 @@ export async function cmdMcpInstall(options: McpCliOptions): Promise<number> {
|
|
|
598
613
|
return 0;
|
|
599
614
|
}
|
|
600
615
|
|
|
616
|
+
/**
|
|
617
|
+
* `mcp install --prod --remote` — write a REMOTE HTTP entry pointing at the
|
|
618
|
+
* stable Cursor MCP gateway for the hosted deployment, for MCP hosts that
|
|
619
|
+
* cannot spawn the stdio proxy (Glass / Sand). The gateway mints/refreshes
|
|
620
|
+
* engineAccess server-side, so the entry never carries a pod hostname or a
|
|
621
|
+
* short-lived port token — only the durable, stable gateway URL.
|
|
622
|
+
*
|
|
623
|
+
* Auth: this headless/CLI entry sends the `agentkit login` API key as a
|
|
624
|
+
* bearer against the user-API-key gateway surface. That key is written to
|
|
625
|
+
* `mcp.json` in plain text (flagged below); a signed-in Cursor client
|
|
626
|
+
* (Glass) can instead use the session gateway surface with no header at all
|
|
627
|
+
* once first-party session attachment ships (see PR follow-ups).
|
|
628
|
+
*/
|
|
629
|
+
async function cmdMcpInstallRemote(options: McpCliOptions): Promise<number> {
|
|
630
|
+
const err = options.err ?? defaultErr;
|
|
631
|
+
const stdout = options.stdout ?? process.stdout;
|
|
632
|
+
|
|
633
|
+
let slug: string;
|
|
634
|
+
try {
|
|
635
|
+
slug = resolveProdSlug({
|
|
636
|
+
dir: options.dir,
|
|
637
|
+
cwd: options.cwd,
|
|
638
|
+
slug: options.slug,
|
|
639
|
+
});
|
|
640
|
+
} catch (error) {
|
|
641
|
+
err(`${describeError(error)}\n`);
|
|
642
|
+
return 1;
|
|
643
|
+
}
|
|
644
|
+
|
|
645
|
+
const resolveAuthImpl = options.resolveDeployAuthImpl ?? resolveDeployAuth;
|
|
646
|
+
const auth = await resolveAuthImpl({
|
|
647
|
+
team: options.team,
|
|
648
|
+
apiKey: options.apiKey,
|
|
649
|
+
fetchImpl: options.fetchImpl,
|
|
650
|
+
err,
|
|
651
|
+
});
|
|
652
|
+
if (typeof auth === "number") {
|
|
653
|
+
return auth;
|
|
654
|
+
}
|
|
655
|
+
|
|
656
|
+
// Verify the deployment resolves before writing config that cannot work.
|
|
657
|
+
// This read is admin-tier, but calling the gateway only needs team
|
|
658
|
+
// membership — so a 403 means "cannot verify", not "cannot use": warn and
|
|
659
|
+
// still write the entry rather than locking members out of their own agent.
|
|
660
|
+
try {
|
|
661
|
+
await auth.client.getDeployment({ teamId: auth.teamId, slug });
|
|
662
|
+
} catch (error) {
|
|
663
|
+
if (error instanceof DeployApiError && error.status === 403) {
|
|
664
|
+
err(
|
|
665
|
+
`Could not verify deployment "${slug}" (reading deployments needs team-admin); writing the entry anyway.\n`
|
|
666
|
+
);
|
|
667
|
+
} else {
|
|
668
|
+
err(`${describeError(error)}\n`);
|
|
669
|
+
if (error instanceof DeployApiError && error.status === 404) {
|
|
670
|
+
err(`Deploy it first: ${CLI} deploy --slug ${slug}\n`);
|
|
671
|
+
}
|
|
672
|
+
return 1;
|
|
673
|
+
}
|
|
674
|
+
}
|
|
675
|
+
|
|
676
|
+
const name = resolveServerName(options.name, slug);
|
|
677
|
+
const url = auth.client.mcpGatewayUrl(auth.teamId, slug);
|
|
678
|
+
const entry: { url: string; headers?: Record<string, string> } = {
|
|
679
|
+
url,
|
|
680
|
+
headers: { Authorization: `Bearer ${auth.apiKey}` },
|
|
681
|
+
};
|
|
682
|
+
|
|
683
|
+
if (options.print === true) {
|
|
684
|
+
stdout.write(
|
|
685
|
+
`${JSON.stringify({ mcpServers: { [name]: entry } }, null, 2)}\n`
|
|
686
|
+
);
|
|
687
|
+
return 0;
|
|
688
|
+
}
|
|
689
|
+
|
|
690
|
+
const path = cursorMcpJsonPath();
|
|
691
|
+
try {
|
|
692
|
+
await upsertMcpJsonEntry(path, name, entry);
|
|
693
|
+
} catch (error) {
|
|
694
|
+
err(`${describeError(error)}\n`);
|
|
695
|
+
return 1;
|
|
696
|
+
}
|
|
697
|
+
|
|
698
|
+
err(
|
|
699
|
+
"note: the API key is written to mcp.json in plain text; it is a durable " +
|
|
700
|
+
"credential for a remote MCP host that cannot spawn the stdio proxy.\n"
|
|
701
|
+
);
|
|
702
|
+
if (options.json === true) {
|
|
703
|
+
stdout.write(`${JSON.stringify({ ok: true, path, name, entry })}\n`);
|
|
704
|
+
return 0;
|
|
705
|
+
}
|
|
706
|
+
stdout.write(
|
|
707
|
+
`Installed remote MCP server "${name}" in ${path}\n` +
|
|
708
|
+
` ${url}\n` +
|
|
709
|
+
"Cursor watches this file; the server appears without a restart.\n"
|
|
710
|
+
);
|
|
711
|
+
return 0;
|
|
712
|
+
}
|
|
713
|
+
|
|
601
714
|
/** `~/.cursor/mcp.json` — the user-level Cursor MCP config. */
|
|
602
715
|
export function cursorMcpJsonPath(
|
|
603
716
|
home: string = process.env.HOME ?? homedir()
|