@jonaspauleta/cursor-bridge 0.2.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.
- package/LICENSE +21 -0
- package/README.md +140 -0
- package/dist/classify.d.ts +8 -0
- package/dist/classify.js +62 -0
- package/dist/classify.js.map +1 -0
- package/dist/codex.classify.d.ts +15 -0
- package/dist/codex.classify.js +34 -0
- package/dist/codex.classify.js.map +1 -0
- package/dist/codex.d.ts +20 -0
- package/dist/codex.js +158 -0
- package/dist/codex.js.map +1 -0
- package/dist/codex.preflight.d.ts +14 -0
- package/dist/codex.preflight.js +27 -0
- package/dist/codex.preflight.js.map +1 -0
- package/dist/cursor.d.ts +17 -0
- package/dist/cursor.js +88 -0
- package/dist/cursor.js.map +1 -0
- package/dist/errors.d.ts +36 -0
- package/dist/errors.js +8 -0
- package/dist/errors.js.map +1 -0
- package/dist/imagegen.tool.d.ts +57 -0
- package/dist/imagegen.tool.js +79 -0
- package/dist/imagegen.tool.js.map +1 -0
- package/dist/index.d.ts +2 -0
- package/dist/index.js +26 -0
- package/dist/index.js.map +1 -0
- package/dist/logger.d.ts +16 -0
- package/dist/logger.js +27 -0
- package/dist/logger.js.map +1 -0
- package/dist/preflight.d.ts +11 -0
- package/dist/preflight.js +35 -0
- package/dist/preflight.js.map +1 -0
- package/dist/runner.d.ts +25 -0
- package/dist/runner.js +35 -0
- package/dist/runner.js.map +1 -0
- package/dist/server.d.ts +5 -0
- package/dist/server.js +19 -0
- package/dist/server.js.map +1 -0
- package/dist/tool.d.ts +38 -0
- package/dist/tool.js +41 -0
- package/dist/tool.js.map +1 -0
- package/dist/validate.d.ts +23 -0
- package/dist/validate.js +112 -0
- package/dist/validate.js.map +1 -0
- package/package.json +50 -0
package/dist/validate.js
ADDED
|
@@ -0,0 +1,112 @@
|
|
|
1
|
+
import { realpathSync, existsSync } from "node:fs";
|
|
2
|
+
import { resolve, sep, dirname } from "node:path";
|
|
3
|
+
import { ValidationError } from "./errors.js";
|
|
4
|
+
const MODES = ["default", "plan", "ask"];
|
|
5
|
+
const MODELS = new Set([
|
|
6
|
+
"composer-2.5-fast",
|
|
7
|
+
"composer-2.5",
|
|
8
|
+
"claude-4.6-sonnet-medium",
|
|
9
|
+
]);
|
|
10
|
+
const SHA_RE = /^[0-9a-f]{7,40}$/;
|
|
11
|
+
export function assertMode(mode) {
|
|
12
|
+
if (!MODES.includes(mode)) {
|
|
13
|
+
throw new ValidationError(`invalid mode: ${JSON.stringify(mode)} (expected default|plan|ask)`);
|
|
14
|
+
}
|
|
15
|
+
return mode;
|
|
16
|
+
}
|
|
17
|
+
export function assertModel(model) {
|
|
18
|
+
if (!MODELS.has(model)) {
|
|
19
|
+
throw new ValidationError(`model not allowlisted: ${JSON.stringify(model)}`);
|
|
20
|
+
}
|
|
21
|
+
return model;
|
|
22
|
+
}
|
|
23
|
+
// Exported for the Part B orchestrator's mechanical SHA resolution: it validates
|
|
24
|
+
// BASE_SHA/HEAD_SHA before they reach the final-gate `git diff` command.
|
|
25
|
+
// Not imported by the server runtime — this is intentional, not dead code.
|
|
26
|
+
export function assertSha(sha) {
|
|
27
|
+
if (!SHA_RE.test(sha)) {
|
|
28
|
+
throw new ValidationError(`not a valid git SHA (need 7-40 hex): ${JSON.stringify(sha)}`);
|
|
29
|
+
}
|
|
30
|
+
return sha;
|
|
31
|
+
}
|
|
32
|
+
/**
|
|
33
|
+
* Returns the canonical (realpath'd) cwd if it is the allowed root or strictly
|
|
34
|
+
* within it. Rejects traversal/expansion tokens before touching the FS, then
|
|
35
|
+
* defeats symlink escapes by canonicalizing both sides and prefix-checking.
|
|
36
|
+
*/
|
|
37
|
+
export function assertWorkspacePath(cwd, allowedRoot) {
|
|
38
|
+
if (cwd.includes("..") || cwd.startsWith("~")) {
|
|
39
|
+
throw new ValidationError(`workspace path rejected (traversal/expansion): ${cwd}`);
|
|
40
|
+
}
|
|
41
|
+
const root = realpathSync(resolve(allowedRoot));
|
|
42
|
+
let real;
|
|
43
|
+
try {
|
|
44
|
+
real = realpathSync(resolve(cwd));
|
|
45
|
+
}
|
|
46
|
+
catch {
|
|
47
|
+
throw new ValidationError(`workspace path does not exist: ${cwd}`);
|
|
48
|
+
}
|
|
49
|
+
if (real !== root && !real.startsWith(root + sep)) {
|
|
50
|
+
throw new ValidationError(`workspace path escapes allowed root: ${cwd}`);
|
|
51
|
+
}
|
|
52
|
+
return real;
|
|
53
|
+
}
|
|
54
|
+
const IMAGE_SIZES = new Set(["auto", "1024x1024", "1536x1024", "1024x1536"]);
|
|
55
|
+
const IMAGE_QUALITIES = new Set(["auto", "low", "medium", "high"]);
|
|
56
|
+
const IMAGE_EXT_RE = /\.(png|jpe?g|webp)$/i;
|
|
57
|
+
const MAX_REFERENCE_IMAGES = 8;
|
|
58
|
+
export function assertCount(count) {
|
|
59
|
+
if (!Number.isInteger(count) || count < 1 || count > 10) {
|
|
60
|
+
throw new ValidationError(`count out of range (expected integer 1-10): ${JSON.stringify(count)}`);
|
|
61
|
+
}
|
|
62
|
+
return count;
|
|
63
|
+
}
|
|
64
|
+
export function assertSize(size) {
|
|
65
|
+
if (!IMAGE_SIZES.has(size)) {
|
|
66
|
+
throw new ValidationError(`size not allowlisted: ${JSON.stringify(size)} (auto|1024x1024|1536x1024|1024x1536)`);
|
|
67
|
+
}
|
|
68
|
+
return size;
|
|
69
|
+
}
|
|
70
|
+
export function assertQuality(quality) {
|
|
71
|
+
if (!IMAGE_QUALITIES.has(quality)) {
|
|
72
|
+
throw new ValidationError(`quality not allowlisted: ${JSON.stringify(quality)} (auto|low|medium|high)`);
|
|
73
|
+
}
|
|
74
|
+
return quality;
|
|
75
|
+
}
|
|
76
|
+
/**
|
|
77
|
+
* Validates an output directory that MAY NOT EXIST YET (unlike assertWorkspacePath,
|
|
78
|
+
* which requires existence). Rejects traversal/expansion, lexically checks the full
|
|
79
|
+
* resolved path against the canonical root, then realpath-checks the nearest existing
|
|
80
|
+
* ancestor to defeat symlink escapes through existing directories.
|
|
81
|
+
*/
|
|
82
|
+
export function assertOutputDir(dir, allowedRoot) {
|
|
83
|
+
if (dir.includes("..") || dir.startsWith("~")) {
|
|
84
|
+
throw new ValidationError(`output dir rejected (traversal/expansion): ${dir}`);
|
|
85
|
+
}
|
|
86
|
+
const root = realpathSync(resolve(allowedRoot));
|
|
87
|
+
const abs = resolve(dir);
|
|
88
|
+
if (abs !== root && !abs.startsWith(root + sep)) {
|
|
89
|
+
throw new ValidationError(`output dir escapes allowed root: ${dir}`);
|
|
90
|
+
}
|
|
91
|
+
let probe = abs;
|
|
92
|
+
while (!existsSync(probe) && dirname(probe) !== probe) {
|
|
93
|
+
probe = dirname(probe);
|
|
94
|
+
}
|
|
95
|
+
const realProbe = realpathSync(probe);
|
|
96
|
+
if (realProbe !== root && !realProbe.startsWith(root + sep)) {
|
|
97
|
+
throw new ValidationError(`output dir escapes allowed root (symlink): ${dir}`);
|
|
98
|
+
}
|
|
99
|
+
return abs;
|
|
100
|
+
}
|
|
101
|
+
export function assertReferenceImages(paths, allowedRoot) {
|
|
102
|
+
if (paths.length > MAX_REFERENCE_IMAGES) {
|
|
103
|
+
throw new ValidationError(`too many reference images (max ${MAX_REFERENCE_IMAGES}): ${paths.length}`);
|
|
104
|
+
}
|
|
105
|
+
return paths.map((p) => {
|
|
106
|
+
if (!IMAGE_EXT_RE.test(p)) {
|
|
107
|
+
throw new ValidationError(`reference image not an allowed type (png|jpg|jpeg|webp): ${p}`);
|
|
108
|
+
}
|
|
109
|
+
return assertWorkspacePath(p, allowedRoot); // requires existence + containment
|
|
110
|
+
});
|
|
111
|
+
}
|
|
112
|
+
//# sourceMappingURL=validate.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"validate.js","sourceRoot":"","sources":["../src/validate.ts"],"names":[],"mappings":"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"}
|
package/package.json
ADDED
|
@@ -0,0 +1,50 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "@jonaspauleta/cursor-bridge",
|
|
3
|
+
"version": "0.2.0",
|
|
4
|
+
"description": "MCP server bridging the cursor-agent and codex CLIs to Claude Code: run_cursor_agent (Composer 2.5) and generate_image (gpt-image-2).",
|
|
5
|
+
"keywords": [
|
|
6
|
+
"mcp",
|
|
7
|
+
"model-context-protocol",
|
|
8
|
+
"claude-code",
|
|
9
|
+
"cursor-agent",
|
|
10
|
+
"codex",
|
|
11
|
+
"gpt-image-2",
|
|
12
|
+
"stdio",
|
|
13
|
+
"ai"
|
|
14
|
+
],
|
|
15
|
+
"license": "MIT",
|
|
16
|
+
"author": "João Paulo Santos <jonaspauleta2@gmail.com>",
|
|
17
|
+
"type": "module",
|
|
18
|
+
"bin": { "cursor-bridge": "dist/index.js" },
|
|
19
|
+
"files": ["dist"],
|
|
20
|
+
"engines": { "node": ">=20" },
|
|
21
|
+
"repository": {
|
|
22
|
+
"type": "git",
|
|
23
|
+
"url": "git+https://github.com/jonaspauleta/cursor-bridge.git"
|
|
24
|
+
},
|
|
25
|
+
"homepage": "https://github.com/jonaspauleta/cursor-bridge#readme",
|
|
26
|
+
"bugs": { "url": "https://github.com/jonaspauleta/cursor-bridge/issues" },
|
|
27
|
+
"publishConfig": { "access": "public" },
|
|
28
|
+
"scripts": {
|
|
29
|
+
"build": "tsc -p tsconfig.build.json",
|
|
30
|
+
"dev": "tsx src/index.ts",
|
|
31
|
+
"start": "node dist/index.js",
|
|
32
|
+
"typecheck": "tsc --noEmit -p tsconfig.json",
|
|
33
|
+
"test": "vitest run",
|
|
34
|
+
"test:watch": "vitest",
|
|
35
|
+
"test:smoke": "RUN_CURSOR_SMOKE=1 vitest run smoke",
|
|
36
|
+
"test:smoke:codex": "RUN_CODEX_SMOKE=1 vitest run codex.smoke",
|
|
37
|
+
"prepare": "npm run build",
|
|
38
|
+
"prepublishOnly": "npm run typecheck && npm test"
|
|
39
|
+
},
|
|
40
|
+
"dependencies": {
|
|
41
|
+
"@modelcontextprotocol/sdk": "^1.29.0",
|
|
42
|
+
"zod": "^4.4.3"
|
|
43
|
+
},
|
|
44
|
+
"devDependencies": {
|
|
45
|
+
"@types/node": "^22.0.0",
|
|
46
|
+
"tsx": "^4.22.3",
|
|
47
|
+
"typescript": "^5.9.0",
|
|
48
|
+
"vitest": "^4.1.0"
|
|
49
|
+
}
|
|
50
|
+
}
|