@velum-labs/cursorkit 0.1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (142) hide show
  1. package/DISCLAIMER.md +12 -0
  2. package/README.md +157 -0
  3. package/dist/src/agentTools/diff.d.ts +11 -0
  4. package/dist/src/agentTools/diff.js +88 -0
  5. package/dist/src/agentTools/policy.d.ts +3 -0
  6. package/dist/src/agentTools/policy.js +12 -0
  7. package/dist/src/agentTools/registry.d.ts +114 -0
  8. package/dist/src/agentTools/registry.js +663 -0
  9. package/dist/src/agentTools/results.d.ts +14 -0
  10. package/dist/src/agentTools/results.js +117 -0
  11. package/dist/src/agentTools/schemas.d.ts +3 -0
  12. package/dist/src/agentTools/schemas.js +89 -0
  13. package/dist/src/agentTools/surface.d.ts +11 -0
  14. package/dist/src/agentTools/surface.js +251 -0
  15. package/dist/src/certs.d.ts +8 -0
  16. package/dist/src/certs.js +34 -0
  17. package/dist/src/ck.d.ts +2 -0
  18. package/dist/src/ck.js +6 -0
  19. package/dist/src/ckLauncher.d.ts +150 -0
  20. package/dist/src/ckLauncher.js +1496 -0
  21. package/dist/src/cli.d.ts +2 -0
  22. package/dist/src/cli.js +265 -0
  23. package/dist/src/config.d.ts +52 -0
  24. package/dist/src/config.js +210 -0
  25. package/dist/src/connectEnvelope.d.ts +16 -0
  26. package/dist/src/connectEnvelope.js +70 -0
  27. package/dist/src/desktop.d.ts +19 -0
  28. package/dist/src/desktop.js +167 -0
  29. package/dist/src/desktopConnectProxy.d.ts +26 -0
  30. package/dist/src/desktopConnectProxy.js +175 -0
  31. package/dist/src/extensions/index.d.ts +2 -0
  32. package/dist/src/extensions/index.js +1 -0
  33. package/dist/src/extensions/registry.d.ts +8 -0
  34. package/dist/src/extensions/registry.js +52 -0
  35. package/dist/src/extensions/types.d.ts +42 -0
  36. package/dist/src/extensions/types.js +1 -0
  37. package/dist/src/fixtures/modelFusion.d.ts +103 -0
  38. package/dist/src/fixtures/modelFusion.js +404 -0
  39. package/dist/src/fixtures/replay.d.ts +9 -0
  40. package/dist/src/fixtures/replay.js +41 -0
  41. package/dist/src/fixtures/sanitizer.d.ts +9 -0
  42. package/dist/src/fixtures/sanitizer.js +43 -0
  43. package/dist/src/fixtures/schema.d.ts +38 -0
  44. package/dist/src/fixtures/schema.js +33 -0
  45. package/dist/src/gen/agent/v1/agent_pb.d.ts +21577 -0
  46. package/dist/src/gen/agent/v1/agent_pb.js +5325 -0
  47. package/dist/src/gen/aiserver/v1/aiserver_pb.d.ts +135242 -0
  48. package/dist/src/gen/aiserver/v1/aiserver_pb.js +34430 -0
  49. package/dist/src/gen/anyrun/v1/anyrun_pb.d.ts +1163 -0
  50. package/dist/src/gen/anyrun/v1/anyrun_pb.js +374 -0
  51. package/dist/src/gen/google/protobuf/google_pb.d.ts +142 -0
  52. package/dist/src/gen/google/protobuf/google_pb.js +54 -0
  53. package/dist/src/gen/internapi/v1/internapi_pb.d.ts +121 -0
  54. package/dist/src/gen/internapi/v1/internapi_pb.js +79 -0
  55. package/dist/src/logger.d.ts +8 -0
  56. package/dist/src/logger.js +37 -0
  57. package/dist/src/modelFusion/cursorHarness.d.ts +146 -0
  58. package/dist/src/modelFusion/cursorHarness.js +647 -0
  59. package/dist/src/modelFusion/index.d.ts +4 -0
  60. package/dist/src/modelFusion/index.js +2 -0
  61. package/dist/src/models/registry.d.ts +22 -0
  62. package/dist/src/models/registry.js +30 -0
  63. package/dist/src/proto.d.ts +13 -0
  64. package/dist/src/proto.js +61 -0
  65. package/dist/src/providers/openai.d.ts +64 -0
  66. package/dist/src/providers/openai.js +355 -0
  67. package/dist/src/redaction.d.ts +4 -0
  68. package/dist/src/redaction.js +65 -0
  69. package/dist/src/routeInventory.d.ts +16 -0
  70. package/dist/src/routeInventory.js +39 -0
  71. package/dist/src/routes.d.ts +37 -0
  72. package/dist/src/routes.js +227 -0
  73. package/dist/src/server.d.ts +50 -0
  74. package/dist/src/server.js +1353 -0
  75. package/dist/src/services/agent.d.ts +1 -0
  76. package/dist/src/services/agent.js +7 -0
  77. package/dist/src/services/agentRun.d.ts +60 -0
  78. package/dist/src/services/agentRun.js +391 -0
  79. package/dist/src/services/chat.d.ts +11 -0
  80. package/dist/src/services/chat.js +47 -0
  81. package/dist/src/services/models.d.ts +10 -0
  82. package/dist/src/services/models.js +216 -0
  83. package/dist/src/services/serverConfig.d.ts +2 -0
  84. package/dist/src/services/serverConfig.js +19 -0
  85. package/dist/src/testing/artifacts.d.ts +14 -0
  86. package/dist/src/testing/artifacts.js +92 -0
  87. package/dist/src/testing/cli.d.ts +4 -0
  88. package/dist/src/testing/cli.js +192 -0
  89. package/dist/src/testing/localBackend.d.ts +24 -0
  90. package/dist/src/testing/localBackend.js +310 -0
  91. package/dist/src/testing/processRunner.d.ts +7 -0
  92. package/dist/src/testing/processRunner.js +74 -0
  93. package/dist/src/testing/runner.d.ts +9 -0
  94. package/dist/src/testing/runner.js +85 -0
  95. package/dist/src/testing/scenarios.d.ts +3 -0
  96. package/dist/src/testing/scenarios.js +2535 -0
  97. package/dist/src/testing/types.d.ts +66 -0
  98. package/dist/src/testing/types.js +1 -0
  99. package/dist/src/tools/baselineInventory.d.ts +12 -0
  100. package/dist/src/tools/baselineInventory.js +680 -0
  101. package/dist/src/tools/checkModelFusionProtocol.d.ts +1 -0
  102. package/dist/src/tools/checkModelFusionProtocol.js +274 -0
  103. package/dist/src/tools/checkReleasePublishConfig.d.ts +1 -0
  104. package/dist/src/tools/checkReleasePublishConfig.js +99 -0
  105. package/dist/src/tools/generateProtoInventory.d.ts +1 -0
  106. package/dist/src/tools/generateProtoInventory.js +89 -0
  107. package/dist/src/tools/normalizeGeneratedCode.d.ts +1 -0
  108. package/dist/src/tools/normalizeGeneratedCode.js +18 -0
  109. package/dist/src/tools/releaseCheck.d.ts +26 -0
  110. package/dist/src/tools/releaseCheck.js +367 -0
  111. package/dist/src/trace.d.ts +39 -0
  112. package/dist/src/trace.js +106 -0
  113. package/dist/src/translation.d.ts +6 -0
  114. package/dist/src/translation.js +22 -0
  115. package/dist/src/upstream.d.ts +20 -0
  116. package/dist/src/upstream.js +270 -0
  117. package/docs/configuration.md +55 -0
  118. package/docs/cursor-app.md +263 -0
  119. package/docs/implementation-inventory.json +609 -0
  120. package/docs/learnings.md +363 -0
  121. package/docs/model-fusion-protocol-origin.json +126 -0
  122. package/docs/model-fusion-protocol.md +110 -0
  123. package/docs/plugin-authoring.md +24 -0
  124. package/docs/proto-inventory.md +1477 -0
  125. package/docs/protocol-surface-audit.md +92 -0
  126. package/docs/protocol.md +52 -0
  127. package/docs/refreshing-protos.md +78 -0
  128. package/docs/release-gates.md +110 -0
  129. package/docs/release-summary.json +86 -0
  130. package/docs/route-contract-manifest.json +288 -0
  131. package/docs/route-policy.json +133 -0
  132. package/docs/service-manifest.json +9490 -0
  133. package/docs/test-manifest.json +155 -0
  134. package/docs/testing-harness.md +204 -0
  135. package/docs/troubleshooting.md +36 -0
  136. package/docs/type-manifest-summary.json +28927 -0
  137. package/package.json +93 -0
  138. package/proto/agent/v1/agent.proto +5371 -0
  139. package/proto/aiserver/v1/aiserver.proto +32944 -0
  140. package/proto/anyrun/v1/anyrun.proto +294 -0
  141. package/proto/google/protobuf/google.proto +37 -0
  142. package/proto/internapi/v1/internapi.proto +32 -0
@@ -0,0 +1,647 @@
1
+ import { create, fromBinary, toBinary } from "@bufbuild/protobuf";
2
+ import { CURSOR_TOOL_SURFACE } from "../agentTools/surface.js";
3
+ import { decodeEnvelopes, encodeEnvelope, isEndStreamEnvelope, } from "../connectEnvelope.js";
4
+ import { assertCursorRunRequestV1, assertCursorRunResultV1, assertHarnessRunRequestV1, assertHarnessRunResultV1, cursorRunResultToHarnessRunResult, MODEL_FUSION_SCHEMA_BUNDLE_HASH, sha256Prefixed, } from "../fixtures/modelFusion.js";
5
+ import { sanitizeModelFusionPayload } from "../fixtures/sanitizer.js";
6
+ import { AgentClientMessageSchema, AgentRunRequestSchema, AgentServerMessageSchema, ConversationActionSchema, RequestedModelSchema, UserMessageActionSchema, UserMessageSchema, } from "../gen/agent/v1/agent_pb.js";
7
+ import { AGENT_RUN_PATH } from "../routes.js";
8
+ export class CursorCapabilityError extends Error {
9
+ issues;
10
+ constructor(issues) {
11
+ super(`Cursor candidate is missing required capabilities: ${issues.map((issue) => issue.capability).join(", ")}`);
12
+ this.name = "CursorCapabilityError";
13
+ this.issues = issues;
14
+ }
15
+ }
16
+ const DEFAULT_PRODUCER = "cursorkit-model-fusion";
17
+ const DEFAULT_VERSION = "0.1.0";
18
+ const DEFAULT_GIT_SHA = "0".repeat(40);
19
+ const CORE_CAPABILITIES = {
20
+ workspace_read: "supported",
21
+ route_observation: "degraded",
22
+ apply_patch: "supported",
23
+ tool_call_loop: "supported",
24
+ };
25
+ export function cursorHarness(options = {}) {
26
+ if (options.adapterMode === "real") {
27
+ return {
28
+ id: "cursor",
29
+ adapterMode: "real",
30
+ capabilities: () => realCursorCapabilities(options),
31
+ runCursorCandidate: (input) => runRealCursorCandidate(input, options),
32
+ };
33
+ }
34
+ return {
35
+ id: "cursor",
36
+ adapterMode: "fixture",
37
+ capabilities: () => cursorCapabilities(),
38
+ runCursorCandidate: (input) => runCursorCandidate(input, options),
39
+ };
40
+ }
41
+ export function runCursorCandidate(input, options = {}) {
42
+ const prepared = prepareCursorCandidateRun(input, options, cursorCapabilities());
43
+ const evidence = {
44
+ ...input.evidence,
45
+ outputSummary: input.evidence?.outputSummary ??
46
+ `Cursor candidate ${input.candidateId} recorded fixture-backed smoke evidence.`,
47
+ };
48
+ return buildCursorCandidateOutput({
49
+ input,
50
+ options,
51
+ prepared,
52
+ adapterMode: "fixture",
53
+ evidenceTier: "smoke",
54
+ artifactBaseUri: options.artifactBaseUri ?? "fixture://cursor/smoke",
55
+ evidence,
56
+ status: "succeeded",
57
+ });
58
+ }
59
+ export async function runRealCursorCandidate(input, options) {
60
+ const prepared = prepareCursorCandidateRun(input, options, realCursorCapabilities(options));
61
+ const cursorRequest = buildCursorRunRequest(input, options, prepared);
62
+ assertCursorRunRequestV1(cursorRequest);
63
+ const clientResult = await options.cursorRunClient.run({
64
+ cursorRequest,
65
+ candidateId: input.candidateId,
66
+ model: input.model,
67
+ workspacePath: cursorRequest.workspace_path,
68
+ timeoutMs: input.timeoutMs,
69
+ capabilities: prepared.capabilities,
70
+ });
71
+ const observedModel = clientResult.observedModel ?? input.evidence?.observedModel;
72
+ const evidence = {
73
+ ...input.evidence,
74
+ rawPayload: clientResult.rawPayload ?? input.evidence?.rawPayload,
75
+ transcript: clientResult.transcript ?? input.evidence?.transcript,
76
+ outputSummary: clientResult.outputSummary ??
77
+ input.evidence?.outputSummary ??
78
+ `Cursor candidate ${input.candidateId} completed through the real Cursor adapter.`,
79
+ observedModel,
80
+ routeInventory: clientResult.routeInventory ?? input.evidence?.routeInventory,
81
+ routeInventoryArtifact: clientResult.routeInventoryArtifact ??
82
+ input.evidence?.routeInventoryArtifact,
83
+ artifacts: [
84
+ ...(input.evidence?.artifacts ?? []),
85
+ ...(clientResult.artifacts ?? []),
86
+ ],
87
+ toolEvidence: [
88
+ ...(input.evidence?.toolEvidence ?? []),
89
+ ...(clientResult.toolEvidence ?? []),
90
+ ],
91
+ };
92
+ const modelEvidence = resolveCursorModelEvidence({
93
+ ...input,
94
+ model: {
95
+ ...input.model,
96
+ id: clientResult.modelId ?? input.model.id,
97
+ endpointId: clientResult.endpointId ?? input.model.endpointId,
98
+ },
99
+ evidence,
100
+ });
101
+ return buildCursorCandidateOutput({
102
+ input,
103
+ options,
104
+ prepared: {
105
+ ...prepared,
106
+ cursorRequest,
107
+ capabilities: effectiveCapabilities({
108
+ ...prepared.capabilities,
109
+ ...(clientResult.capabilities ?? {}),
110
+ }, input.request.requested_capabilities),
111
+ modelEvidence,
112
+ },
113
+ adapterMode: "real",
114
+ evidenceTier: "real",
115
+ artifactBaseUri: options.artifactBaseUri ??
116
+ `cursor-bridge://agent-run/${safeId(input.candidateId)}`,
117
+ evidence,
118
+ status: clientResult.status ?? "succeeded",
119
+ });
120
+ }
121
+ function prepareCursorCandidateRun(input, options, actualCapabilities) {
122
+ assertHarnessRunRequestV1(input.request);
123
+ const capabilityPolicy = options.capabilityPolicy ?? "record-and-degrade";
124
+ const capabilities = effectiveCapabilities(actualCapabilities, input.request.requested_capabilities);
125
+ const overrideIssues = capabilityOverrideIssues(input.request.requested_capabilities, capabilities);
126
+ const missingCapabilities = capabilityIssues(input.requiredCapabilities ?? [], capabilities);
127
+ const diagnostics = diagnosticsFor([
128
+ ...overrideIssues,
129
+ ...missingCapabilities,
130
+ ]);
131
+ if (capabilityPolicy === "fail-closed" && diagnostics.length > 0) {
132
+ throw new CursorCapabilityError([
133
+ ...overrideIssues,
134
+ ...missingCapabilities,
135
+ ]);
136
+ }
137
+ return {
138
+ now: (options.now ?? (() => new Date()))().toISOString(),
139
+ cursorRunId: `cursor_run_${safeId(input.candidateId)}`,
140
+ capabilities,
141
+ diagnostics,
142
+ missingCapabilities,
143
+ modelEvidence: resolveCursorModelEvidence(input),
144
+ };
145
+ }
146
+ function buildCursorRunRequest(input, options, prepared) {
147
+ return {
148
+ ...metadata("cursor-run-request.v1", options, prepared.now),
149
+ cursor_run_id: prepared.cursorRunId,
150
+ harness_request_id: input.request.request_id,
151
+ workspace_path: input.workspacePath ?? input.worktreePath ?? ".",
152
+ prompt: input.request.prompt,
153
+ prompt_hash: input.request.prompt_hash,
154
+ requested_model: prepared.modelEvidence.requestedModel,
155
+ allowed_tools: input.request.allowed_tools ?? supportedCursorToolNames(),
156
+ side_effects: input.request.side_effects,
157
+ requested_capabilities: input.request.requested_capabilities,
158
+ };
159
+ }
160
+ function buildCursorCandidateOutput(input) {
161
+ const runInput = input.input;
162
+ const modelEvidence = input.prepared.modelEvidence;
163
+ const cursorRequest = input.prepared.cursorRequest ??
164
+ buildCursorRunRequest(runInput, input.options, input.prepared);
165
+ const rawPayload = input.evidence.rawPayload ??
166
+ input.evidence.transcript ??
167
+ JSON.stringify({
168
+ prompt: runInput.request.prompt,
169
+ candidateId: runInput.candidateId,
170
+ model: modelEvidence.requestedModel,
171
+ adapterMode: input.adapterMode,
172
+ evidenceTier: input.evidenceTier,
173
+ });
174
+ const sanitized = sanitizeModelFusionPayload({ rawPayload });
175
+ const transcriptArtifact = {
176
+ artifact_id: `artifact_${safeId(runInput.candidateId)}_cursor_transcript`,
177
+ kind: "transcript",
178
+ uri: `${input.artifactBaseUri}/${safeId(runInput.candidateId)}-transcript-redacted.json`,
179
+ hash: sanitized.redacted_hash,
180
+ redaction_status: input.adapterMode === "fixture" ? "synthetic" : sanitized.redactionStatus,
181
+ };
182
+ const routeInventoryArtifact = input.evidence.routeInventoryArtifact ??
183
+ (input.evidence.routeInventory
184
+ ? routeInventoryArtifactFor({
185
+ candidateId: runInput.candidateId,
186
+ artifactBaseUri: input.artifactBaseUri,
187
+ summary: input.evidence.routeInventory,
188
+ })
189
+ : undefined);
190
+ const artifacts = [
191
+ ...artifactRefsForEvidence({
192
+ candidateId: runInput.candidateId,
193
+ artifactBaseUri: input.artifactBaseUri,
194
+ evidence: input.evidence,
195
+ }),
196
+ ...(routeInventoryArtifact ? [routeInventoryArtifact] : []),
197
+ ];
198
+ const cursorResult = {
199
+ ...metadata("cursor-run-result.v1", input.options, input.prepared.now),
200
+ cursor_run_id: input.prepared.cursorRunId,
201
+ harness_request_id: runInput.request.request_id,
202
+ mapped_harness_result_id: `harness_result_${safeId(runInput.candidateId)}`,
203
+ status: input.status,
204
+ output_summary: input.evidence.outputSummary ??
205
+ `Cursor candidate ${runInput.candidateId} completed.`,
206
+ transcript_artifact: transcriptArtifact,
207
+ ...(artifacts.length > 0 ? { artifacts } : {}),
208
+ capabilities: input.prepared.capabilities,
209
+ requested_model: modelEvidence.requestedModel,
210
+ observed_model: modelEvidence.observedModel,
211
+ model_id: modelEvidence.modelId,
212
+ endpoint_id: modelEvidence.endpointId,
213
+ ...(input.prepared.diagnostics.length > 0
214
+ ? { diagnostics: input.prepared.diagnostics }
215
+ : {}),
216
+ raw_hash: sanitized.raw_hash,
217
+ redacted_hash: sanitized.redacted_hash,
218
+ };
219
+ assertCursorRunRequestV1(cursorRequest);
220
+ assertCursorRunResultV1(cursorResult);
221
+ const mapped = cursorRunResultToHarnessRunResult(cursorResult);
222
+ const toolEvidence = input.evidence.toolEvidence ?? [];
223
+ const harnessResult = {
224
+ ...mapped,
225
+ candidate_ids: [runInput.candidateId],
226
+ metadata: {
227
+ ...(mapped.metadata ?? {}),
228
+ adapter_mode: input.adapterMode,
229
+ evidence_tier: input.evidenceTier,
230
+ fixture: input.adapterMode === "fixture",
231
+ artifact_base_uri: input.artifactBaseUri,
232
+ candidate_id: runInput.candidateId,
233
+ model_id: runInput.model.id,
234
+ model: runInput.model.model,
235
+ endpoint_id: runInput.model.endpointId ?? runInput.model.id,
236
+ requested_model: modelEvidence.requestedModel,
237
+ observed_model: modelEvidence.observedModel,
238
+ model_resolution_status: modelEvidence.status,
239
+ model_resolution_reason: modelEvidence.reason,
240
+ ...(runInput.worktreePath
241
+ ? { worktree_path: runInput.worktreePath }
242
+ : {}),
243
+ missing_capabilities: input.prepared.missingCapabilities,
244
+ route_inventory: input.evidence.routeInventory ?? null,
245
+ ...(routeInventoryArtifact
246
+ ? { route_inventory_evidence: routeInventoryArtifact }
247
+ : {}),
248
+ tool_evidence_count: toolEvidence.length,
249
+ ...(toolEvidence.length > 0 ? { tool_evidence: toolEvidence } : {}),
250
+ ...(runInput.metadata ?? {}),
251
+ },
252
+ };
253
+ assertHarnessRunResultV1(harnessResult);
254
+ return {
255
+ cursorRequest,
256
+ cursorResult,
257
+ harnessResult,
258
+ missingCapabilities: input.prepared.missingCapabilities,
259
+ metadata: harnessResult.metadata ?? {},
260
+ };
261
+ }
262
+ function artifactRefsForEvidence(input) {
263
+ return [
264
+ ...(input.evidence.diff
265
+ ? [
266
+ artifactRefForContent({
267
+ candidateId: input.candidateId,
268
+ artifactBaseUri: input.artifactBaseUri,
269
+ suffix: "cursor_patch",
270
+ filename: `${safeId(input.candidateId)}.patch`,
271
+ kind: "patch",
272
+ content: input.evidence.diff,
273
+ }),
274
+ ]
275
+ : []),
276
+ ...(input.evidence.log
277
+ ? [
278
+ artifactRefForContent({
279
+ candidateId: input.candidateId,
280
+ artifactBaseUri: input.artifactBaseUri,
281
+ suffix: "cursor_log",
282
+ filename: `${safeId(input.candidateId)}.log`,
283
+ kind: "log",
284
+ content: input.evidence.log,
285
+ }),
286
+ ]
287
+ : []),
288
+ ...(input.evidence.artifacts ?? []).map((artifact, index) => artifactRefForEvidence({
289
+ candidateId: input.candidateId,
290
+ artifactBaseUri: input.artifactBaseUri,
291
+ artifact,
292
+ index,
293
+ })),
294
+ ];
295
+ }
296
+ function artifactRefForContent(input) {
297
+ return {
298
+ artifact_id: `artifact_${safeId(input.candidateId)}_${input.suffix}`,
299
+ kind: input.kind,
300
+ uri: `${input.artifactBaseUri}/${input.filename}`,
301
+ hash: sha256Prefixed(input.content),
302
+ redaction_status: "redacted",
303
+ };
304
+ }
305
+ function artifactRefForEvidence(input) {
306
+ const suffix = `${input.artifact.kind}_${String(input.index + 1)}`;
307
+ const artifactId = input.artifact.artifactId ??
308
+ `artifact_${safeId(input.candidateId)}_cursor_${suffix}`;
309
+ const uri = input.artifact.uri ??
310
+ `${input.artifactBaseUri}/${safeId(input.candidateId)}-${suffix}.json`;
311
+ return {
312
+ artifact_id: artifactId,
313
+ kind: input.artifact.kind,
314
+ uri,
315
+ hash: input.artifact.hash ??
316
+ sha256Prefixed(input.artifact.content ?? `${artifactId}:${uri}`),
317
+ redaction_status: input.artifact.redactionStatus ?? "redacted",
318
+ };
319
+ }
320
+ function realCursorCapabilities(options) {
321
+ return {
322
+ ...cursorCapabilities(),
323
+ ...(options.cursorRunClient.capabilities?.() ?? {}),
324
+ ...(options.capabilities ?? {}),
325
+ };
326
+ }
327
+ export function cursorCapabilities() {
328
+ const toolCapabilities = {};
329
+ for (const tool of CURSOR_TOOL_SURFACE) {
330
+ if (tool.openAIToolName === undefined)
331
+ continue;
332
+ toolCapabilities[`tool:${tool.openAIToolName}`] = statusForToolSupport(tool.support);
333
+ }
334
+ return { ...CORE_CAPABILITIES, ...toolCapabilities };
335
+ }
336
+ export function createCursorBridgeRunClient(options) {
337
+ return {
338
+ capabilities: () => ({
339
+ workspace_read: "supported",
340
+ route_observation: "degraded",
341
+ apply_patch: "supported",
342
+ tool_call_loop: "supported",
343
+ }),
344
+ run: async (input) => {
345
+ const response = await postAgentRunToBridge(options, input);
346
+ const body = Buffer.from(await response.arrayBuffer());
347
+ const transcript = decodeAgentRunTranscript(body);
348
+ const routeInventory = {
349
+ observedRoutes: 1,
350
+ passThroughRoutes: 0,
351
+ interceptedRoutes: response.ok ? 1 : 0,
352
+ degradedRoutes: response.ok ? 0 : 1,
353
+ failedRouteCount: response.ok ? 0 : 1,
354
+ observedPaths: [AGENT_RUN_PATH],
355
+ diagnosis: [
356
+ response.ok
357
+ ? "Agent Run was submitted through the Cursor bridge route."
358
+ : `Agent Run bridge request failed with HTTP ${String(response.status)}.`,
359
+ ],
360
+ };
361
+ const rawPayload = stableJson({
362
+ schema: "cursor-agent-run-transcript.v1",
363
+ bridge_path: AGENT_RUN_PATH,
364
+ status: response.status,
365
+ headers: responseHeaders(response),
366
+ transcript,
367
+ });
368
+ return {
369
+ status: response.ok ? "succeeded" : "failed",
370
+ outputSummary: transcript.text.length > 0
371
+ ? transcript.text
372
+ : `Cursor bridge Agent Run returned HTTP ${String(response.status)}.`,
373
+ transcript: rawPayload,
374
+ rawPayload,
375
+ observedModel: input.model.model,
376
+ routeInventory,
377
+ artifacts: [
378
+ {
379
+ kind: "log",
380
+ content: stableJson({
381
+ bridge_path: AGENT_RUN_PATH,
382
+ status: response.status,
383
+ body_bytes: body.byteLength,
384
+ text_chars: transcript.text.length,
385
+ }),
386
+ },
387
+ ],
388
+ toolEvidence: [
389
+ {
390
+ bridge_path: AGENT_RUN_PATH,
391
+ observed_tool_events: transcript.toolEventCount,
392
+ },
393
+ ],
394
+ };
395
+ },
396
+ };
397
+ }
398
+ async function postAgentRunToBridge(options, input) {
399
+ const fetchImpl = options.fetch ?? fetch;
400
+ const controller = new AbortController();
401
+ let timeout;
402
+ if (input.timeoutMs !== undefined) {
403
+ timeout = setTimeout(() => controller.abort(), input.timeoutMs);
404
+ }
405
+ try {
406
+ return await fetchImpl(agentRunUrl(options.bridgeBaseUrl), {
407
+ method: "POST",
408
+ headers: {
409
+ "content-type": "application/connect+proto",
410
+ ...(options.authToken !== undefined
411
+ ? { authorization: `Bearer ${options.authToken}` }
412
+ : {}),
413
+ ...(options.headers ?? {}),
414
+ },
415
+ body: new Uint8Array(encodeEnvelope(toBinary(AgentClientMessageSchema, create(AgentClientMessageSchema, {
416
+ runRequest: create(AgentRunRequestSchema, {
417
+ requestedModel: create(RequestedModelSchema, {
418
+ modelId: input.cursorRequest.requested_model ?? input.model.model,
419
+ }),
420
+ action: create(ConversationActionSchema, {
421
+ userMessageAction: create(UserMessageActionSchema, {
422
+ userMessage: create(UserMessageSchema, {
423
+ text: input.cursorRequest.prompt,
424
+ }),
425
+ }),
426
+ }),
427
+ }),
428
+ })))),
429
+ signal: controller.signal,
430
+ });
431
+ }
432
+ finally {
433
+ if (timeout !== undefined) {
434
+ clearTimeout(timeout);
435
+ }
436
+ }
437
+ }
438
+ function agentRunUrl(bridgeBaseUrl) {
439
+ return new URL(AGENT_RUN_PATH, bridgeBaseUrl).toString();
440
+ }
441
+ function decodeAgentRunTranscript(body) {
442
+ const textParts = [];
443
+ let messageCount = 0;
444
+ let toolEventCount = 0;
445
+ try {
446
+ for (const envelope of decodeEnvelopes(body)) {
447
+ if (isEndStreamEnvelope(envelope) || envelope.payload.length === 0) {
448
+ continue;
449
+ }
450
+ const message = fromBinary(AgentServerMessageSchema, envelope.payload);
451
+ messageCount += 1;
452
+ const delta = message.interactionUpdate?.textDelta?.text;
453
+ if (delta !== undefined && delta.length > 0) {
454
+ textParts.push(delta);
455
+ }
456
+ if (message.execServerMessage !== undefined) {
457
+ toolEventCount += 1;
458
+ }
459
+ }
460
+ }
461
+ catch (error) {
462
+ textParts.push(`Agent Run response decode failed: ${error instanceof Error ? error.message : String(error)}`);
463
+ }
464
+ return {
465
+ text: textParts.join(""),
466
+ messageCount,
467
+ toolEventCount,
468
+ };
469
+ }
470
+ function responseHeaders(response) {
471
+ const headers = {};
472
+ response.headers.forEach((value, key) => {
473
+ if (/authorization|cookie|token|key|secret/i.test(key)) {
474
+ headers[key] = "[REDACTED]";
475
+ return;
476
+ }
477
+ headers[key] = value.slice(0, 1_000);
478
+ });
479
+ return headers;
480
+ }
481
+ function effectiveCapabilities(actual, requested) {
482
+ const result = { ...actual };
483
+ for (const [capability, requestedStatus] of Object.entries(requested)) {
484
+ const actualStatus = actual[capability] ?? "unknown";
485
+ result[capability] = weakerCapability(actualStatus, requestedStatus);
486
+ }
487
+ return result;
488
+ }
489
+ function capabilityOverrideIssues(requested, effective) {
490
+ return Object.entries(requested).flatMap(([capability, requestedStatus]) => {
491
+ const status = effective[capability] ?? "unknown";
492
+ if (capabilityRank(status) >= capabilityRank(requestedStatus))
493
+ return [];
494
+ return [
495
+ {
496
+ capability,
497
+ status,
498
+ requestedStatus,
499
+ reason: `Cursor capability ${capability} requested ${requestedStatus} but is ${status}`,
500
+ },
501
+ ];
502
+ });
503
+ }
504
+ function metadata(schema, options, createdAt) {
505
+ return {
506
+ schema,
507
+ schema_version: "v1",
508
+ schema_bundle_hash: MODEL_FUSION_SCHEMA_BUNDLE_HASH,
509
+ producer: options.producer ?? DEFAULT_PRODUCER,
510
+ producer_version: options.producerVersion ?? DEFAULT_VERSION,
511
+ producer_git_sha: options.producerGitSha ?? DEFAULT_GIT_SHA,
512
+ created_at: createdAt,
513
+ };
514
+ }
515
+ function capabilityIssues(required, capabilities) {
516
+ return required.flatMap((capability) => {
517
+ const status = capabilities[capability] ?? "unknown";
518
+ if (status === "supported")
519
+ return [];
520
+ return [
521
+ {
522
+ capability,
523
+ status,
524
+ requestedStatus: "supported",
525
+ reason: `Cursor capability ${capability} is ${status}`,
526
+ },
527
+ ];
528
+ });
529
+ }
530
+ function diagnosticsFor(issues) {
531
+ const seen = new Set();
532
+ return issues.flatMap((issue) => {
533
+ const key = `${issue.capability}:${issue.status}:${issue.requestedStatus ?? ""}`;
534
+ if (seen.has(key))
535
+ return [];
536
+ seen.add(key);
537
+ return [
538
+ {
539
+ kind: "capability_missing",
540
+ message: issue.reason,
541
+ retryable: false,
542
+ capability: issue.capability,
543
+ status: issue.status,
544
+ ...(issue.requestedStatus
545
+ ? { requested_status: issue.requestedStatus }
546
+ : {}),
547
+ },
548
+ ];
549
+ });
550
+ }
551
+ function weakerCapability(actual, requested) {
552
+ return capabilityRank(actual) <= capabilityRank(requested)
553
+ ? actual
554
+ : requested;
555
+ }
556
+ function capabilityRank(status) {
557
+ switch (status) {
558
+ case "supported":
559
+ return 3;
560
+ case "degraded":
561
+ return 2;
562
+ case "unsupported":
563
+ return 1;
564
+ case "unknown":
565
+ return 0;
566
+ default: {
567
+ const exhaustive = status;
568
+ return exhaustive;
569
+ }
570
+ }
571
+ }
572
+ function resolveCursorModelEvidence(input) {
573
+ const requestedModel = input.requestedModel ?? input.model.model;
574
+ const observedModel = input.evidence?.observedModel ?? input.model.model;
575
+ const explicitStatus = input.evidence?.modelResolutionStatus;
576
+ const status = explicitStatus ??
577
+ (requestedModel === observedModel
578
+ ? "matched"
579
+ : observedModel === "unknown"
580
+ ? "unknown"
581
+ : "blocked_override");
582
+ return {
583
+ requestedModel,
584
+ observedModel,
585
+ modelId: input.model.id,
586
+ endpointId: input.model.endpointId ?? input.model.id,
587
+ status,
588
+ reason: input.evidence?.modelResolutionReason ??
589
+ (status === "matched"
590
+ ? "requested model matched observed provider model"
591
+ : status === "unknown"
592
+ ? "observed model was not available in fixture evidence"
593
+ : "requested model override did not match observed provider model"),
594
+ };
595
+ }
596
+ function routeInventoryArtifactFor(input) {
597
+ const payload = stableJson({
598
+ schema: "route-inventory-evidence.v1",
599
+ redaction_status: "redacted",
600
+ desktop_route_stability: "observed-only",
601
+ summary: input.summary,
602
+ });
603
+ return {
604
+ artifact_id: `artifact_${safeId(input.candidateId)}_route_inventory`,
605
+ kind: "metrics",
606
+ uri: `${input.artifactBaseUri}/${safeId(input.candidateId)}-route-inventory.json`,
607
+ hash: sha256Prefixed(payload),
608
+ redaction_status: "redacted",
609
+ };
610
+ }
611
+ function stableJson(value) {
612
+ if (value === null ||
613
+ typeof value === "boolean" ||
614
+ typeof value === "number") {
615
+ return JSON.stringify(value);
616
+ }
617
+ if (typeof value === "string")
618
+ return JSON.stringify(value);
619
+ if (Array.isArray(value))
620
+ return `[${value.map(stableJson).join(",")}]`;
621
+ return `{${Object.keys(value)
622
+ .sort()
623
+ .map((key) => `${JSON.stringify(key)}:${stableJson(value[key] ?? null)}`)
624
+ .join(",")}}`;
625
+ }
626
+ function statusForToolSupport(support) {
627
+ switch (support) {
628
+ case "supported":
629
+ return "supported";
630
+ case "policy-gated":
631
+ return "degraded";
632
+ case "internal":
633
+ case "not-supported":
634
+ return "unsupported";
635
+ default:
636
+ return "unknown";
637
+ }
638
+ }
639
+ function supportedCursorToolNames() {
640
+ return CURSOR_TOOL_SURFACE.flatMap((tool) => tool.openAIToolName === undefined ||
641
+ statusForToolSupport(tool.support) === "unsupported"
642
+ ? []
643
+ : [tool.openAIToolName]);
644
+ }
645
+ function safeId(value) {
646
+ return value.replace(/[^A-Za-z0-9_.:-]/g, "_");
647
+ }
@@ -0,0 +1,4 @@
1
+ export { createCursorBridgeRunClient, cursorCapabilities, cursorHarness, CursorCapabilityError, runRealCursorCandidate, runCursorCandidate, } from "./cursorHarness.js";
2
+ export type { CursorAdapterMode, CursorArtifactEvidence, CursorCapabilityIssue, CursorCapabilityPolicy, CursorCandidateEvidence, CursorBridgeRunClientOptions, CursorEvidenceTier, CursorFixtureHarness, CursorHarness, CursorHarnessModel, CursorHarnessOptions, CursorRealHarness, CursorRealHarnessOptions, CursorRouteInventorySummary, CursorRunClient, CursorRunClientRequest, CursorRunClientResult, RunCursorCandidateInput, RunCursorCandidateOutput, } from "./cursorHarness.js";
3
+ export { assertCursorRunRequestV1, assertCursorRunResultV1, assertHarnessRunRequestV1, assertHarnessRunResultV1, cursorRunResultToHarnessRunResult, MODEL_FUSION_SCHEMA_BUNDLE_HASH, sha256Prefixed, } from "../fixtures/modelFusion.js";
4
+ export type { ArtifactRef, CursorRunRequestV1, CursorRunResultV1, HarnessRunRequestV1, HarnessRunResultV1, JsonValue, ModelFusionCapabilityStatus, ModelFusionStatus, } from "../fixtures/modelFusion.js";
@@ -0,0 +1,2 @@
1
+ export { createCursorBridgeRunClient, cursorCapabilities, cursorHarness, CursorCapabilityError, runRealCursorCandidate, runCursorCandidate, } from "./cursorHarness.js";
2
+ export { assertCursorRunRequestV1, assertCursorRunResultV1, assertHarnessRunRequestV1, assertHarnessRunResultV1, cursorRunResultToHarnessRunResult, MODEL_FUSION_SCHEMA_BUNDLE_HASH, sha256Prefixed, } from "../fixtures/modelFusion.js";
@@ -0,0 +1,22 @@
1
+ import type { LocalModelConfig } from "../config.js";
2
+ import type { ChatMessage, OpenAICompletionEvent, OpenAIStreamOptions, OpenAIToolDefinition } from "../providers/openai.js";
3
+ export interface RegisteredModel {
4
+ id: string;
5
+ displayName: string;
6
+ baseUrl: string;
7
+ apiKey: string;
8
+ contextTokenLimit: number;
9
+ provider: ModelProvider;
10
+ }
11
+ export interface ModelProvider {
12
+ readonly name: string;
13
+ streamCompletion(messages: ChatMessage[], options?: OpenAIStreamOptions): AsyncGenerator<string>;
14
+ streamCompletionEvents?(messages: ChatMessage[], tools?: OpenAIToolDefinition[], options?: OpenAIStreamOptions): AsyncGenerator<OpenAICompletionEvent>;
15
+ }
16
+ export declare class ModelRegistry {
17
+ private readonly models;
18
+ register(model: RegisteredModel): void;
19
+ get(id: string | undefined): RegisteredModel | undefined;
20
+ list(): RegisteredModel[];
21
+ }
22
+ export declare function registerConfiguredModels(registry: ModelRegistry, configs: LocalModelConfig[], providerFactory: (config: LocalModelConfig) => ModelProvider): void;