@velum-labs/cursorkit 0.1.0 → 0.1.2

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/dist/src/cli.d.ts CHANGED
@@ -1,2 +1,3 @@
1
1
  #!/usr/bin/env node
2
- export {};
2
+ import { Command } from "commander";
3
+ export declare function buildCursorkitProgram(): Command;
package/dist/src/cli.js CHANGED
@@ -1,265 +1,37 @@
1
1
  #!/usr/bin/env node
2
- import fs from "node:fs";
3
- import path from "node:path";
4
- import { loadConfig } from "./config.js";
5
- import { loadTlsMaterial } from "./certs.js";
6
- import { desktopCertificateStatus, desktopDnsStatus, desktopEnv, desktopTrustCommand, localModelBackendStatus, upstreamReachabilityStatus, writeDesktopCertificate, } from "./desktop.js";
7
- import { createLogger } from "./logger.js";
8
- import { assertCursorRunRequestV1, assertCursorRunResultV1, assertHarnessRunRequestV1, assertHarnessRunResultV1, } from "./fixtures/modelFusion.js";
9
- import { listProtoFiles, loadCursorProto, resolveProtoDirectory, } from "./proto.js";
10
- import { createBridgeRuntime, startServer } from "./server.js";
11
- const HELP = `cursorkit
12
-
13
- Usage:
14
- cursorkit serve Start the local bridge
15
- cursorkit doctor Check local configuration and proto availability
16
- cursorkit desktop-cert Generate local TLS material for Cursor desktop proxying
17
- cursorkit desktop-proxy Start the bridge with Cursor desktop proxy defaults
18
- cursorkit desktop-doctor Check Cursor desktop proxy prerequisites
19
- cursorkit capture Print capture-mode guidance
20
- cursorkit fixtures Validate committed fixture metadata
21
- cursorkit --help Show this help
22
-
2
+ import { Command } from "commander";
3
+ import { registerCk } from "./ckLauncher.js";
4
+ import { registerDoctor } from "./commands/doctor.js";
5
+ import { registerMaintenance } from "./commands/maintenance.js";
6
+ import { registerServe } from "./commands/serve.js";
7
+ const ENV_HELP = `
23
8
  Environment:
24
9
  BRIDGE_HOST=127.0.0.1
25
10
  BRIDGE_PORT=9443
26
11
  CURSOR_UPSTREAM_BASE_URL=https://example.cursor-backend.local
27
12
  MODEL_BASE_URL=http://localhost:8080/v1
28
- MODEL_NAME=local-model
29
- `;
30
- async function main(argv) {
31
- const command = parseCommand(argv);
32
- if (command === "help") {
33
- console.log(HELP);
13
+ MODEL_NAME=local-model`;
14
+ export function buildCursorkitProgram() {
15
+ const program = new Command();
16
+ program
17
+ .name("cursorkit")
18
+ .description("local model bridge for Cursor")
19
+ .addHelpText("after", ENV_HELP);
20
+ registerServe(program);
21
+ registerDoctor(program);
22
+ registerMaintenance(program);
23
+ registerCk(program);
24
+ return program;
25
+ }
26
+ async function main() {
27
+ const program = buildCursorkitProgram();
28
+ if (process.argv.slice(2).length === 0) {
29
+ program.outputHelp();
34
30
  return;
35
31
  }
36
- const config = loadConfig(command === "desktop-proxy" || command === "desktop-doctor"
37
- ? desktopEnv(process.env)
38
- : process.env);
39
- const logger = createLogger(config.logLevel);
40
- switch (command) {
41
- case "serve": {
42
- const runtime = await createBridgeRuntime(config, logger);
43
- installGracefulShutdown(await startServer(runtime), logger);
44
- break;
45
- }
46
- case "doctor": {
47
- await doctor(config);
48
- break;
49
- }
50
- case "capture": {
51
- capture(config);
52
- break;
53
- }
54
- case "fixtures": {
55
- validateFixtures(config.captureDir);
56
- break;
57
- }
58
- case "desktop-cert": {
59
- await desktopCert();
60
- break;
61
- }
62
- case "desktop-proxy": {
63
- const runtime = await createBridgeRuntime(config, logger);
64
- installGracefulShutdown(await startServer(runtime), logger);
65
- break;
66
- }
67
- case "desktop-doctor": {
68
- await doctor(config);
69
- await desktopDoctor(config);
70
- break;
71
- }
72
- default: {
73
- const exhaustive = command;
74
- throw new Error(`Unhandled command: ${exhaustive}`);
75
- }
76
- }
77
- }
78
- function parseCommand(argv) {
79
- const first = argv[2];
80
- if (first === undefined ||
81
- first === "--help" ||
82
- first === "-h" ||
83
- first === "help") {
84
- return "help";
85
- }
86
- if (first === "serve" ||
87
- first === "doctor" ||
88
- first === "capture" ||
89
- first === "fixtures" ||
90
- first === "desktop-cert" ||
91
- first === "desktop-proxy" ||
92
- first === "desktop-doctor") {
93
- return first;
94
- }
95
- throw new Error(`Unknown command: ${first}\n\n${HELP}`);
96
- }
97
- async function doctor(config) {
98
- const checks = [];
99
- const protoDir = resolveProtoDirectory();
100
- checks.push(["proto directory", protoDir]);
101
- checks.push(["proto files", String(listProtoFiles(protoDir).length)]);
102
- const proto = await loadCursorProto();
103
- checks.push([
104
- "available models type",
105
- proto.AvailableModelsResponse.fullName,
106
- ]);
107
- checks.push(["chat type", proto.StreamUnifiedChatRequestWithTools.fullName]);
108
- checks.push(["bind", `${config.host}:${config.port}`]);
109
- checks.push(["tls", config.useTls ? "enabled" : "disabled"]);
110
- checks.push(["upstream", config.upstreamBaseUrl ?? "not configured"]);
111
- checks.push([
112
- "local models",
113
- config.models.map((model) => model.id).join(", "),
114
- ]);
115
- checks.push([
116
- "capture",
117
- config.captureEnabled ? `enabled -> ${config.captureDir}` : "disabled",
118
- ]);
119
- checks.push(["fail-open", String(config.failOpen)]);
120
- checks.push([
121
- "auth",
122
- config.authToken === undefined ? "disabled" : "enabled",
123
- ]);
124
- checks.push([
125
- "non-localhost unsafe mode",
126
- String(config.unsafeAllowNonLocalhost),
127
- ]);
128
- if (config.useTls) {
129
- const tls = await loadTlsMaterial(config);
130
- checks.push([
131
- "tls material",
132
- tls.generated
133
- ? "generated self-signed dev certificate"
134
- : "custom certificate",
135
- ]);
136
- }
137
- for (const [name, value] of checks) {
138
- console.log(`${name}: ${value}`);
139
- }
140
- if (config.upstreamBaseUrl === undefined) {
141
- console.warn("warning: pass-through traffic needs CURSOR_UPSTREAM_BASE_URL");
142
- }
143
- if (config.captureEnabled) {
144
- console.warn("warning: capture mode treats traffic as sensitive; sanitize before committing fixtures");
145
- }
146
- if (config.modelPayloadLogging === "full") {
147
- console.warn("warning: BRIDGE_LOG_MODEL_PAYLOADS=full may log prompt and tool payloads; use only for local debugging");
148
- }
149
- if (config.unsafeAllowNonLocalhost) {
150
- console.warn("warning: non-localhost unsafe mode exposes the bridge without built-in auth");
151
- }
152
- }
153
- function installGracefulShutdown(server, logger) {
154
- let shuttingDown = false;
155
- const shutdown = (signal) => {
156
- if (shuttingDown) {
157
- logger.warn("forcing bridge shutdown", { signal });
158
- process.exit(1);
159
- }
160
- shuttingDown = true;
161
- logger.info("shutting down bridge", { signal });
162
- const forceTimer = setTimeout(() => {
163
- logger.error("bridge shutdown timed out", { signal });
164
- process.exit(1);
165
- }, 5_000);
166
- server.close((error) => {
167
- clearTimeout(forceTimer);
168
- if (error !== undefined) {
169
- logger.error("bridge shutdown failed", { error: error.message });
170
- process.exitCode = 1;
171
- }
172
- process.exit();
173
- });
174
- };
175
- process.once("SIGINT", shutdown);
176
- process.once("SIGTERM", shutdown);
177
- }
178
- async function desktopCert() {
179
- const cert = await writeDesktopCertificate();
180
- console.log(`cert: ${cert.certPath}`);
181
- console.log(`key: ${cert.keyPath}`);
182
- console.log("");
183
- console.log("Manual macOS trust command:");
184
- console.log(desktopTrustCommand(cert.certPath).join(" "));
185
- console.log("");
186
- console.log("Then start with:");
187
- console.log(`BRIDGE_CERT_PATH=${cert.certPath} BRIDGE_KEY_PATH=${cert.keyPath} cursorkit desktop-proxy`);
188
- }
189
- async function desktopDoctor(config) {
190
- const checks = [];
191
- checks.push(["desktop mode", String(config.desktopMode)]);
192
- checks.push(["public origin", config.publicOrigin ?? "not configured"]);
193
- checks.push(["tls hostnames", config.tlsHostnames.join(", ")]);
194
- checks.push(["route inventory", String(config.routeInventoryEnabled)]);
195
- checks.push(["desktop upstream", config.upstreamBaseUrl ?? "not configured"]);
196
- checks.push([
197
- "desktop upstream connect",
198
- config.upstreamConnectHost === undefined
199
- ? "system DNS"
200
- : `${config.upstreamConnectHost}${config.upstreamConnectPort === undefined ? "" : `:${config.upstreamConnectPort}`}`,
201
- ]);
202
- checks.push(["desktop cert", desktopCertificateStatus(config)]);
203
- checks.push(["desktop dns", await desktopDnsStatus(config)]);
204
- checks.push([
205
- "upstream reachability",
206
- await upstreamReachabilityStatus(config),
207
- ]);
208
- checks.push(["local model backend", await localModelBackendStatus(config)]);
209
- for (const [name, value] of checks) {
210
- console.log(`${name}: ${value}`);
211
- }
212
- }
213
- function capture(config) {
214
- console.log(`captureEnabled: ${config.captureEnabled}`);
215
- console.log(`captureDir: ${config.captureDir}`);
216
- console.log("Capture mode is explicit and sanitized fixture writing is required before committing data.");
217
- }
218
- function validateFixtures(captureDir) {
219
- const modelFusionCount = validateModelFusionFixtures();
220
- if (!fs.existsSync(captureDir)) {
221
- console.log(`No fixture capture directory found at ${captureDir}`);
222
- console.log(`Validated ${modelFusionCount} model-fusion fixture file(s)`);
223
- return;
224
- }
225
- const files = fs
226
- .readdirSync(captureDir)
227
- .filter((file) => file.endsWith(".json"));
228
- for (const file of files) {
229
- const fullPath = path.join(captureDir, file);
230
- const parsed = JSON.parse(fs.readFileSync(fullPath, "utf8"));
231
- if (parsed.redaction?.status !== "sanitized") {
232
- throw new Error(`${fullPath} is missing redaction.status=sanitized`);
233
- }
234
- }
235
- console.log(`Validated ${files.length} capture fixture file(s) and ${modelFusionCount} model-fusion fixture file(s)`);
236
- }
237
- function validateModelFusionFixtures() {
238
- const root = path.resolve("fixtures", "model-fusion-contract");
239
- if (!fs.existsSync(root))
240
- return 0;
241
- let count = 0;
242
- const validators = {
243
- "harness-run-request.v1": assertHarnessRunRequestV1,
244
- "harness-run-result.v1": assertHarnessRunResultV1,
245
- "cursor-run-request.v1": assertCursorRunRequestV1,
246
- "cursor-run-result.v1": assertCursorRunResultV1,
247
- };
248
- for (const [schema, validate] of Object.entries(validators)) {
249
- const schemaDir = path.join(root, schema);
250
- if (!fs.existsSync(schemaDir))
251
- continue;
252
- for (const file of fs
253
- .readdirSync(schemaDir)
254
- .filter((item) => item.endsWith(".json"))) {
255
- const fixturePath = path.join(schemaDir, file);
256
- validate(JSON.parse(fs.readFileSync(fixturePath, "utf8")));
257
- count++;
258
- }
259
- }
260
- return count;
32
+ await program.parseAsync(process.argv);
261
33
  }
262
- main(process.argv).catch((error) => {
34
+ main().catch((error) => {
263
35
  console.error(error instanceof Error ? error.message : String(error));
264
36
  process.exitCode = 1;
265
37
  });
@@ -0,0 +1,2 @@
1
+ import type { Command } from "commander";
2
+ export declare function registerDoctor(program: Command): void;
@@ -0,0 +1,129 @@
1
+ import { loadConfig } from "../config.js";
2
+ import { loadTlsMaterial } from "../certs.js";
3
+ import { desktopCertificateStatus, desktopDnsStatus, desktopEnv, localModelBackendStatus, upstreamReachabilityStatus, } from "../desktop.js";
4
+ import { listProtoFiles, loadCursorProto, resolveProtoDirectory, } from "../proto.js";
5
+ import { bold, brandHeader, green, uiStream, withSpinner, } from "../ui/index.js";
6
+ import { renderCheck, warningLine } from "./render.js";
7
+ function write(line) {
8
+ uiStream().write(`${line}\n`);
9
+ }
10
+ async function runDoctor(config) {
11
+ write(`\n${brandHeader("environment check")}\n`);
12
+ const proto = await withSpinner("loading Cursor proto", () => loadCursorProto());
13
+ const protoDir = resolveProtoDirectory();
14
+ const checks = [
15
+ { label: "proto directory", detail: protoDir },
16
+ { label: "proto files", detail: String(listProtoFiles(protoDir).length) },
17
+ {
18
+ label: "available models type",
19
+ detail: proto.AvailableModelsResponse.fullName,
20
+ },
21
+ {
22
+ label: "chat type",
23
+ detail: proto.StreamUnifiedChatRequestWithTools.fullName,
24
+ },
25
+ { label: "bind", detail: `${config.host}:${config.port}` },
26
+ { label: "tls", detail: config.useTls ? "enabled" : "disabled" },
27
+ {
28
+ label: "upstream",
29
+ ok: config.upstreamBaseUrl !== undefined,
30
+ detail: config.upstreamBaseUrl ?? "not configured",
31
+ hint: "pass-through traffic needs CURSOR_UPSTREAM_BASE_URL",
32
+ },
33
+ {
34
+ label: "local models",
35
+ detail: config.models.map((model) => model.id).join(", "),
36
+ },
37
+ {
38
+ label: "capture",
39
+ detail: config.captureEnabled
40
+ ? `enabled -> ${config.captureDir}`
41
+ : "disabled",
42
+ },
43
+ { label: "fail-open", detail: String(config.failOpen) },
44
+ {
45
+ label: "auth",
46
+ detail: config.authToken === undefined ? "disabled" : "enabled",
47
+ },
48
+ {
49
+ label: "non-localhost unsafe mode",
50
+ detail: String(config.unsafeAllowNonLocalhost),
51
+ },
52
+ ];
53
+ if (config.useTls) {
54
+ const tls = await loadTlsMaterial(config);
55
+ checks.push({
56
+ label: "tls material",
57
+ detail: tls.generated
58
+ ? "generated self-signed dev certificate"
59
+ : "custom certificate",
60
+ });
61
+ }
62
+ write(bold("configuration"));
63
+ for (const check of checks)
64
+ write(` ${renderCheck(check)}`);
65
+ const warnings = [];
66
+ if (config.captureEnabled) {
67
+ warnings.push("capture mode treats traffic as sensitive; sanitize before committing fixtures");
68
+ }
69
+ if (config.modelPayloadLogging === "full") {
70
+ warnings.push("BRIDGE_LOG_MODEL_PAYLOADS=full may log prompt and tool payloads; use only for local debugging");
71
+ }
72
+ if (config.unsafeAllowNonLocalhost) {
73
+ warnings.push("non-localhost unsafe mode exposes the bridge without built-in auth");
74
+ }
75
+ if (warnings.length > 0) {
76
+ write("");
77
+ for (const warning of warnings)
78
+ write(` ${warningLine(warning)}`);
79
+ }
80
+ }
81
+ async function runDesktopDoctor(config) {
82
+ write(`\n${bold("desktop proxy")}\n`);
83
+ const checks = [
84
+ { label: "desktop mode", detail: String(config.desktopMode) },
85
+ { label: "public origin", detail: config.publicOrigin ?? "not configured" },
86
+ { label: "tls hostnames", detail: config.tlsHostnames.join(", ") },
87
+ { label: "route inventory", detail: String(config.routeInventoryEnabled) },
88
+ {
89
+ label: "desktop upstream",
90
+ detail: config.upstreamBaseUrl ?? "not configured",
91
+ },
92
+ {
93
+ label: "desktop upstream connect",
94
+ detail: config.upstreamConnectHost === undefined
95
+ ? "system DNS"
96
+ : `${config.upstreamConnectHost}${config.upstreamConnectPort === undefined ? "" : `:${config.upstreamConnectPort}`}`,
97
+ },
98
+ { label: "desktop cert", detail: desktopCertificateStatus(config) },
99
+ { label: "desktop dns", detail: await desktopDnsStatus(config) },
100
+ {
101
+ label: "upstream reachability",
102
+ detail: await upstreamReachabilityStatus(config),
103
+ },
104
+ {
105
+ label: "local model backend",
106
+ detail: await localModelBackendStatus(config),
107
+ },
108
+ ];
109
+ for (const check of checks)
110
+ write(` ${renderCheck(check)}`);
111
+ write("");
112
+ write(green("desktop checks complete."));
113
+ }
114
+ export function registerDoctor(program) {
115
+ program
116
+ .command("doctor")
117
+ .description("check local configuration and proto availability")
118
+ .action(async () => {
119
+ await runDoctor(loadConfig(process.env));
120
+ });
121
+ program
122
+ .command("desktop-doctor")
123
+ .description("check Cursor desktop proxy prerequisites")
124
+ .action(async () => {
125
+ const config = loadConfig(desktopEnv(process.env));
126
+ await runDoctor(config);
127
+ await runDesktopDoctor(config);
128
+ });
129
+ }
@@ -0,0 +1,2 @@
1
+ import type { Command } from "commander";
2
+ export declare function registerMaintenance(program: Command): void;
@@ -0,0 +1,94 @@
1
+ import fs from "node:fs";
2
+ import path from "node:path";
3
+ import { loadConfig } from "../config.js";
4
+ import { desktopTrustCommand, writeDesktopCertificate } from "../desktop.js";
5
+ import { assertCursorRunRequestV1, assertCursorRunResultV1, assertHarnessRunRequestV1, assertHarnessRunResultV1, } from "../fixtures/modelFusion.js";
6
+ import { bold, brandHeader, dim, done, note, uiStream, withSpinner, } from "../ui/index.js";
7
+ function write(line) {
8
+ uiStream().write(`${line}\n`);
9
+ }
10
+ function capture(captureDir, captureEnabled) {
11
+ write(`\n${brandHeader("capture")}\n`);
12
+ write(`${dim("captureEnabled:")} ${captureEnabled}`);
13
+ write(`${dim("captureDir:")} ${captureDir}`);
14
+ note("Capture mode is explicit; sanitized fixture writing is required before committing data.");
15
+ }
16
+ function validateModelFusionFixtures() {
17
+ const root = path.resolve("fixtures", "model-fusion-contract");
18
+ if (!fs.existsSync(root))
19
+ return 0;
20
+ let count = 0;
21
+ const validators = {
22
+ "harness-run-request.v1": assertHarnessRunRequestV1,
23
+ "harness-run-result.v1": assertHarnessRunResultV1,
24
+ "cursor-run-request.v1": assertCursorRunRequestV1,
25
+ "cursor-run-result.v1": assertCursorRunResultV1,
26
+ };
27
+ for (const [schema, validate] of Object.entries(validators)) {
28
+ const schemaDir = path.join(root, schema);
29
+ if (!fs.existsSync(schemaDir))
30
+ continue;
31
+ for (const file of fs
32
+ .readdirSync(schemaDir)
33
+ .filter((item) => item.endsWith(".json"))) {
34
+ const fixturePath = path.join(schemaDir, file);
35
+ validate(JSON.parse(fs.readFileSync(fixturePath, "utf8")));
36
+ count++;
37
+ }
38
+ }
39
+ return count;
40
+ }
41
+ function validateFixtures(captureDir) {
42
+ write(`\n${brandHeader("fixtures")}\n`);
43
+ const modelFusionCount = validateModelFusionFixtures();
44
+ if (!fs.existsSync(captureDir)) {
45
+ note(`No fixture capture directory found at ${captureDir}`);
46
+ done(`Validated ${modelFusionCount} model-fusion fixture file(s)`);
47
+ return;
48
+ }
49
+ const files = fs
50
+ .readdirSync(captureDir)
51
+ .filter((file) => file.endsWith(".json"));
52
+ for (const file of files) {
53
+ const fullPath = path.join(captureDir, file);
54
+ const parsed = JSON.parse(fs.readFileSync(fullPath, "utf8"));
55
+ if (parsed.redaction?.status !== "sanitized") {
56
+ throw new Error(`${fullPath} is missing redaction.status=sanitized`);
57
+ }
58
+ }
59
+ done(`Validated ${files.length} capture fixture file(s) and ${modelFusionCount} model-fusion fixture file(s)`);
60
+ }
61
+ async function desktopCert() {
62
+ write(`\n${brandHeader("desktop certificate")}\n`);
63
+ const cert = await withSpinner("generating self-signed certificate", () => writeDesktopCertificate());
64
+ write(`${dim("cert:")} ${cert.certPath}`);
65
+ write(`${dim("key:")} ${cert.keyPath}`);
66
+ write("");
67
+ write(bold("Manual macOS trust command:"));
68
+ write(desktopTrustCommand(cert.certPath).join(" "));
69
+ write("");
70
+ write(bold("Then start with:"));
71
+ write(`BRIDGE_CERT_PATH=${cert.certPath} BRIDGE_KEY_PATH=${cert.keyPath} cursorkit desktop-proxy`);
72
+ }
73
+ export function registerMaintenance(program) {
74
+ program
75
+ .command("capture")
76
+ .description("print capture-mode guidance")
77
+ .action(() => {
78
+ const config = loadConfig(process.env);
79
+ capture(config.captureDir, config.captureEnabled);
80
+ });
81
+ program
82
+ .command("fixtures")
83
+ .description("validate committed fixture metadata")
84
+ .action(() => {
85
+ const config = loadConfig(process.env);
86
+ validateFixtures(config.captureDir);
87
+ });
88
+ program
89
+ .command("desktop-cert")
90
+ .description("generate local TLS material for Cursor desktop proxying")
91
+ .action(async () => {
92
+ await desktopCert();
93
+ });
94
+ }
@@ -0,0 +1,14 @@
1
+ /**
2
+ * A single diagnostic line. `ok === undefined` renders as a neutral bullet
3
+ * (informational), while `true`/`false` render as a tick/cross. A `hint` is
4
+ * shown on the next line only for failed checks.
5
+ */
6
+ export type Check = {
7
+ label: string;
8
+ ok?: boolean;
9
+ detail?: string;
10
+ hint?: string;
11
+ };
12
+ export declare function renderCheck(check: Check): string;
13
+ /** A yellow advisory line (non-fatal warnings). */
14
+ export declare function warningLine(message: string): string;
@@ -0,0 +1,17 @@
1
+ import { dim, glyph, gray, green, red, yellow } from "../ui/index.js";
2
+ export function renderCheck(check) {
3
+ const mark = check.ok === undefined
4
+ ? gray(glyph.bullet())
5
+ : check.ok
6
+ ? green(glyph.tick())
7
+ : red(glyph.cross());
8
+ const detail = check.detail !== undefined ? ` ${dim(check.detail)}` : "";
9
+ const hint = check.ok === false && check.hint !== undefined
10
+ ? `\n ${yellow(glyph.arrow())} ${check.hint}`
11
+ : "";
12
+ return `${mark} ${check.label}${detail}${hint}`;
13
+ }
14
+ /** A yellow advisory line (non-fatal warnings). */
15
+ export function warningLine(message) {
16
+ return `${yellow(glyph.warn())} ${message}`;
17
+ }
@@ -0,0 +1,2 @@
1
+ import type { Command } from "commander";
2
+ export declare function registerServe(program: Command): void;
@@ -0,0 +1,52 @@
1
+ import { loadConfig } from "../config.js";
2
+ import { desktopEnv } from "../desktop.js";
3
+ import { createLogger } from "../logger.js";
4
+ import { createBridgeRuntime, startServer } from "../server.js";
5
+ import { brandHeader, bold, dim, glyph, green, uiStream } from "../ui/index.js";
6
+ function installGracefulShutdown(server, logger) {
7
+ let shuttingDown = false;
8
+ const shutdown = (signal) => {
9
+ if (shuttingDown) {
10
+ logger.warn("forcing bridge shutdown", { signal });
11
+ process.exit(1);
12
+ }
13
+ shuttingDown = true;
14
+ logger.info("shutting down bridge", { signal });
15
+ const forceTimer = setTimeout(() => {
16
+ logger.error("bridge shutdown timed out", { signal });
17
+ process.exit(1);
18
+ }, 5_000);
19
+ server.close((error) => {
20
+ clearTimeout(forceTimer);
21
+ if (error !== undefined) {
22
+ logger.error("bridge shutdown failed", { error: error.message });
23
+ process.exitCode = 1;
24
+ }
25
+ process.exit();
26
+ });
27
+ };
28
+ process.once("SIGINT", shutdown);
29
+ process.once("SIGTERM", shutdown);
30
+ }
31
+ async function startBridge(env, mode) {
32
+ const config = loadConfig(env);
33
+ const logger = createLogger(config.logLevel);
34
+ uiStream().write(`\n${brandHeader(mode === "desktop" ? "desktop proxy" : "bridge")}\n` +
35
+ `${dim("bind:")} ${bold(`${config.host}:${config.port}`)} ${dim("tls:")} ${config.useTls ? green(glyph.tick()) : "off"}\n\n`);
36
+ const runtime = await createBridgeRuntime(config, logger);
37
+ installGracefulShutdown(await startServer(runtime), logger);
38
+ }
39
+ export function registerServe(program) {
40
+ program
41
+ .command("serve")
42
+ .description("start the local bridge")
43
+ .action(async () => {
44
+ await startBridge(process.env, "default");
45
+ });
46
+ program
47
+ .command("desktop-proxy")
48
+ .description("start the bridge with Cursor desktop proxy defaults")
49
+ .action(async () => {
50
+ await startBridge(desktopEnv(process.env), "desktop");
51
+ });
52
+ }
@@ -0,0 +1,10 @@
1
+ import type { LocalModelConfig } from "./config.js";
2
+ /**
3
+ * Builders that shape the Cursor desktop `applicationUser` state and local
4
+ * model catalog entries. Extracted from `ckLauncher` so the (large) launcher
5
+ * module is not also responsible for the desktop state-seed schema. These are
6
+ * pure data transforms over plain JSON-shaped records.
7
+ */
8
+ export declare function mergeLocalAgentBackendUrlsIntoApplicationUser(applicationUser: Record<string, unknown>, agentOrigin: string): void;
9
+ export declare function mergeLocalDesktopModelsIntoApplicationUser(applicationUser: Record<string, unknown>, models: LocalModelConfig[]): void;
10
+ export declare function buildLocalDesktopModelEntry(model: LocalModelConfig): Record<string, unknown>;