zero-config-cli-bridge 1.0.1 → 1.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.
- package/dist/executor.d.ts +5 -1
- package/dist/executor.d.ts.map +1 -1
- package/dist/executor.js +17 -15
- package/dist/executor.js.map +1 -1
- package/dist/index.js +54 -21
- package/dist/index.js.map +1 -1
- package/dist/schema.d.ts +7 -2
- package/dist/schema.d.ts.map +1 -1
- package/dist/schema.js +87 -71
- package/dist/schema.js.map +1 -1
- package/dist/security.d.ts +10 -1
- package/dist/security.d.ts.map +1 -1
- package/dist/security.js +27 -17
- package/dist/security.js.map +1 -1
- package/package.json +9 -1
package/dist/executor.d.ts
CHANGED
|
@@ -3,5 +3,9 @@ export interface ExecuteResult {
|
|
|
3
3
|
stderr: string;
|
|
4
4
|
exitCode: number;
|
|
5
5
|
}
|
|
6
|
-
|
|
6
|
+
/**
|
|
7
|
+
* Executes a binary directly with an args array.
|
|
8
|
+
* NO shell intermediary — shell injection is structurally impossible.
|
|
9
|
+
*/
|
|
10
|
+
export declare function executeCommand(bin: string, args: string[]): Promise<ExecuteResult>;
|
|
7
11
|
//# sourceMappingURL=executor.d.ts.map
|
package/dist/executor.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"executor.d.ts","sourceRoot":"","sources":["../src/executor.ts"],"names":[],"mappings":"AAEA,MAAM,WAAW,aAAa;IAC5B,MAAM,EAAE,MAAM,CAAC;IACf,MAAM,EAAE,MAAM,CAAC;IACf,QAAQ,EAAE,MAAM,CAAC;CAClB;
|
|
1
|
+
{"version":3,"file":"executor.d.ts","sourceRoot":"","sources":["../src/executor.ts"],"names":[],"mappings":"AAEA,MAAM,WAAW,aAAa;IAC5B,MAAM,EAAE,MAAM,CAAC;IACf,MAAM,EAAE,MAAM,CAAC;IACf,QAAQ,EAAE,MAAM,CAAC;CAClB;AAaD;;;GAGG;AACH,wBAAgB,cAAc,CAAC,GAAG,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,EAAE,GAAG,OAAO,CAAC,aAAa,CAAC,CAgClF"}
|
package/dist/executor.js
CHANGED
|
@@ -1,29 +1,31 @@
|
|
|
1
1
|
import { spawn } from 'child_process';
|
|
2
|
-
|
|
2
|
+
// Raw character cap — fires only for non-JSON (error messages, plain text).
|
|
3
|
+
// Structured JSON output is truncated at the item level in index.ts.
|
|
4
|
+
const MAX_OUTPUT_CHARS = 10_000_000; // 10 MB hard ceiling
|
|
3
5
|
const TRUNCATION_MSG = '\n...[Output truncated. Use grep/jq to filter]';
|
|
4
|
-
const TIMEOUT_MS =
|
|
5
|
-
function truncate(
|
|
6
|
-
if (
|
|
7
|
-
return
|
|
8
|
-
return
|
|
6
|
+
const TIMEOUT_MS = 15_000;
|
|
7
|
+
function truncate(s) {
|
|
8
|
+
if (s.length <= MAX_OUTPUT_CHARS)
|
|
9
|
+
return s;
|
|
10
|
+
return s.slice(0, MAX_OUTPUT_CHARS) + TRUNCATION_MSG;
|
|
9
11
|
}
|
|
10
|
-
|
|
12
|
+
/**
|
|
13
|
+
* Executes a binary directly with an args array.
|
|
14
|
+
* NO shell intermediary — shell injection is structurally impossible.
|
|
15
|
+
*/
|
|
16
|
+
export function executeCommand(bin, args) {
|
|
11
17
|
return new Promise((resolve, reject) => {
|
|
12
|
-
const proc = spawn(
|
|
18
|
+
const proc = spawn(bin, args, {
|
|
13
19
|
env: { ...process.env, CI: 'true' },
|
|
14
20
|
stdio: ['ignore', 'pipe', 'pipe'],
|
|
15
21
|
});
|
|
16
22
|
let stdoutBuf = '';
|
|
17
23
|
let stderrBuf = '';
|
|
18
|
-
proc.stdout.on('data', (chunk) => {
|
|
19
|
-
|
|
20
|
-
});
|
|
21
|
-
proc.stderr.on('data', (chunk) => {
|
|
22
|
-
stderrBuf += chunk.toString();
|
|
23
|
-
});
|
|
24
|
+
proc.stdout.on('data', (chunk) => { stdoutBuf += chunk.toString(); });
|
|
25
|
+
proc.stderr.on('data', (chunk) => { stderrBuf += chunk.toString(); });
|
|
24
26
|
const timer = setTimeout(() => {
|
|
25
27
|
proc.kill('SIGKILL');
|
|
26
|
-
reject(new Error(`Command timed out after ${TIMEOUT_MS}ms
|
|
28
|
+
reject(new Error(`Command timed out after ${TIMEOUT_MS}ms`));
|
|
27
29
|
}, TIMEOUT_MS);
|
|
28
30
|
proc.on('close', (code) => {
|
|
29
31
|
clearTimeout(timer);
|
package/dist/executor.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"executor.js","sourceRoot":"","sources":["../src/executor.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,KAAK,EAAE,MAAM,eAAe,CAAC;AAQtC,MAAM,
|
|
1
|
+
{"version":3,"file":"executor.js","sourceRoot":"","sources":["../src/executor.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,KAAK,EAAE,MAAM,eAAe,CAAC;AAQtC,4EAA4E;AAC5E,qEAAqE;AACrE,MAAM,gBAAgB,GAAG,UAAU,CAAC,CAAC,qBAAqB;AAC1D,MAAM,cAAc,GAAG,gDAAgD,CAAC;AACxE,MAAM,UAAU,GAAG,MAAM,CAAC;AAE1B,SAAS,QAAQ,CAAC,CAAS;IACzB,IAAI,CAAC,CAAC,MAAM,IAAI,gBAAgB;QAAE,OAAO,CAAC,CAAC;IAC3C,OAAO,CAAC,CAAC,KAAK,CAAC,CAAC,EAAE,gBAAgB,CAAC,GAAG,cAAc,CAAC;AACvD,CAAC;AAED;;;GAGG;AACH,MAAM,UAAU,cAAc,CAAC,GAAW,EAAE,IAAc;IACxD,OAAO,IAAI,OAAO,CAAC,CAAC,OAAO,EAAE,MAAM,EAAE,EAAE;QACrC,MAAM,IAAI,GAAG,KAAK,CAAC,GAAG,EAAE,IAAI,EAAE;YAC5B,GAAG,EAAE,EAAE,GAAG,OAAO,CAAC,GAAG,EAAE,EAAE,EAAE,MAAM,EAAE;YACnC,KAAK,EAAE,CAAC,QAAQ,EAAE,MAAM,EAAE,MAAM,CAAC;SAClC,CAAC,CAAC;QAEH,IAAI,SAAS,GAAG,EAAE,CAAC;QACnB,IAAI,SAAS,GAAG,EAAE,CAAC;QAEnB,IAAI,CAAC,MAAM,CAAC,EAAE,CAAC,MAAM,EAAE,CAAC,KAAa,EAAE,EAAE,GAAG,SAAS,IAAI,KAAK,CAAC,QAAQ,EAAE,CAAC,CAAC,CAAC,CAAC,CAAC;QAC9E,IAAI,CAAC,MAAM,CAAC,EAAE,CAAC,MAAM,EAAE,CAAC,KAAa,EAAE,EAAE,GAAG,SAAS,IAAI,KAAK,CAAC,QAAQ,EAAE,CAAC,CAAC,CAAC,CAAC,CAAC;QAE9E,MAAM,KAAK,GAAG,UAAU,CAAC,GAAG,EAAE;YAC5B,IAAI,CAAC,IAAI,CAAC,SAAS,CAAC,CAAC;YACrB,MAAM,CAAC,IAAI,KAAK,CAAC,2BAA2B,UAAU,IAAI,CAAC,CAAC,CAAC;QAC/D,CAAC,EAAE,UAAU,CAAC,CAAC;QAEf,IAAI,CAAC,EAAE,CAAC,OAAO,EAAE,CAAC,IAAmB,EAAE,EAAE;YACvC,YAAY,CAAC,KAAK,CAAC,CAAC;YACpB,OAAO,CAAC;gBACN,MAAM,EAAE,QAAQ,CAAC,SAAS,CAAC;gBAC3B,MAAM,EAAE,QAAQ,CAAC,SAAS,CAAC;gBAC3B,QAAQ,EAAE,IAAI,IAAI,CAAC;aACpB,CAAC,CAAC;QACL,CAAC,CAAC,CAAC;QAEH,IAAI,CAAC,EAAE,CAAC,OAAO,EAAE,CAAC,GAAU,EAAE,EAAE;YAC9B,YAAY,CAAC,KAAK,CAAC,CAAC;YACpB,MAAM,CAAC,GAAG,CAAC,CAAC;QACd,CAAC,CAAC,CAAC;IACL,CAAC,CAAC,CAAC;AACL,CAAC"}
|
package/dist/index.js
CHANGED
|
@@ -3,52 +3,85 @@ import { Server } from '@modelcontextprotocol/sdk/server/index.js';
|
|
|
3
3
|
import { StdioServerTransport } from '@modelcontextprotocol/sdk/server/stdio.js';
|
|
4
4
|
import { CallToolRequestSchema, ListToolsRequestSchema, } from '@modelcontextprotocol/sdk/types.js';
|
|
5
5
|
import { executeCommand } from './executor.js';
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
6
|
+
const MAX_JSON_ITEMS = 30;
|
|
7
|
+
const TRUNCATION_MSG = `\n...[Output truncated at ${MAX_JSON_ITEMS} items. Use --limit or filters to narrow results.]`;
|
|
8
|
+
/**
|
|
9
|
+
* Ensures the output returned to the LLM is always valid JSON.
|
|
10
|
+
* If the output is a JSON array, caps it at MAX_JSON_ITEMS to prevent
|
|
11
|
+
* context exhaustion. Falls back to raw text if parsing fails.
|
|
12
|
+
*/
|
|
13
|
+
function toJsonOutput(raw) {
|
|
14
|
+
try {
|
|
15
|
+
const parsed = JSON.parse(raw);
|
|
16
|
+
if (Array.isArray(parsed)) {
|
|
17
|
+
if (parsed.length > MAX_JSON_ITEMS) {
|
|
18
|
+
return JSON.stringify(parsed.slice(0, MAX_JSON_ITEMS), null, 2) + TRUNCATION_MSG;
|
|
19
|
+
}
|
|
20
|
+
return JSON.stringify(parsed, null, 2);
|
|
21
|
+
}
|
|
22
|
+
return JSON.stringify(parsed, null, 2);
|
|
23
|
+
}
|
|
24
|
+
catch {
|
|
25
|
+
return raw; // non-JSON response (errors, etc.) returned as-is
|
|
26
|
+
}
|
|
27
|
+
}
|
|
28
|
+
import { validateSubcommand, validateArgs } from './security.js';
|
|
29
|
+
import { buildToolDefinitions, buildGhArgs } from './schema.js';
|
|
30
|
+
const server = new Server({ name: 'zero-config-cli-bridge', version: '1.1.0' }, { capabilities: { tools: {} } });
|
|
31
|
+
let toolRegistry = new Map();
|
|
32
|
+
server.setRequestHandler(ListToolsRequestSchema, async () => ({
|
|
33
|
+
tools: Array.from(toolRegistry.values()).map(({ name, description, inputSchema }) => ({
|
|
34
|
+
name,
|
|
35
|
+
description,
|
|
36
|
+
inputSchema,
|
|
37
|
+
})),
|
|
38
|
+
}));
|
|
12
39
|
server.setRequestHandler(CallToolRequestSchema, async (request) => {
|
|
13
40
|
const { name: toolName, arguments: rawArgs } = request.params;
|
|
14
41
|
const args = (rawArgs ?? {});
|
|
15
|
-
const
|
|
16
|
-
|
|
42
|
+
const tool = toolRegistry.get(toolName);
|
|
43
|
+
if (!tool) {
|
|
44
|
+
return {
|
|
45
|
+
content: [{ type: 'text', text: `Error: Unknown tool "${toolName}".` }],
|
|
46
|
+
isError: true,
|
|
47
|
+
};
|
|
48
|
+
}
|
|
49
|
+
// Security: whitelist subcommand + validate arg values
|
|
17
50
|
try {
|
|
18
|
-
|
|
51
|
+
validateSubcommand(tool.subcommand.join(' '));
|
|
52
|
+
validateArgs(args);
|
|
19
53
|
}
|
|
20
54
|
catch (err) {
|
|
21
|
-
const msg = err instanceof Error ? err.message : String(err);
|
|
22
55
|
return {
|
|
23
|
-
content: [{ type: 'text', text:
|
|
56
|
+
content: [{ type: 'text', text: err instanceof Error ? err.message : String(err) }],
|
|
24
57
|
isError: true,
|
|
25
58
|
};
|
|
26
59
|
}
|
|
27
|
-
//
|
|
60
|
+
// Direct spawn — no shell, no injection surface
|
|
61
|
+
const ghArgs = buildGhArgs(tool, args);
|
|
28
62
|
let result;
|
|
29
63
|
try {
|
|
30
|
-
result = await executeCommand(
|
|
64
|
+
result = await executeCommand('gh', ghArgs);
|
|
31
65
|
}
|
|
32
66
|
catch (err) {
|
|
33
|
-
const msg = err instanceof Error ? err.message : String(err);
|
|
34
67
|
return {
|
|
35
|
-
content: [{ type: 'text', text: `Execution error: ${
|
|
68
|
+
content: [{ type: 'text', text: `Execution error: ${err instanceof Error ? err.message : String(err)}` }],
|
|
36
69
|
isError: true,
|
|
37
70
|
};
|
|
38
71
|
}
|
|
39
|
-
const
|
|
40
|
-
|
|
41
|
-
`(no output, exit code ${result.exitCode})`;
|
|
42
|
-
const isError = result.exitCode !== 0;
|
|
72
|
+
const raw = result.stdout || result.stderr || `(no output, exit code ${result.exitCode})`;
|
|
73
|
+
const output = toJsonOutput(raw);
|
|
43
74
|
return {
|
|
44
75
|
content: [{ type: 'text', text: output }],
|
|
45
|
-
isError,
|
|
76
|
+
isError: result.exitCode !== 0,
|
|
46
77
|
};
|
|
47
78
|
});
|
|
48
79
|
async function main() {
|
|
80
|
+
// Probe local gh binary for available capabilities before accepting requests
|
|
81
|
+
const tools = await buildToolDefinitions();
|
|
82
|
+
toolRegistry = new Map(tools.map((t) => [t.name, t]));
|
|
49
83
|
const transport = new StdioServerTransport();
|
|
50
84
|
await server.connect(transport);
|
|
51
|
-
// Server is running on stdio - no console output to avoid corrupting MCP protocol
|
|
52
85
|
}
|
|
53
86
|
main().catch((err) => {
|
|
54
87
|
process.stderr.write(`Fatal error: ${err}\n`);
|
package/dist/index.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,MAAM,EAAE,MAAM,2CAA2C,CAAC;AACnE,OAAO,EAAE,oBAAoB,EAAE,MAAM,2CAA2C,CAAC;AACjF,OAAO,EACL,qBAAqB,EACrB,sBAAsB,GACvB,MAAM,oCAAoC,CAAC;AAE5C,OAAO,EAAE,cAAc,EAAE,MAAM,eAAe,CAAC;
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"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"}
|
package/dist/schema.d.ts
CHANGED
|
@@ -9,7 +9,12 @@ export interface ToolDefinition {
|
|
|
9
9
|
}>;
|
|
10
10
|
required?: string[];
|
|
11
11
|
};
|
|
12
|
+
/** gh subcommand tokens, e.g. ['issue', 'list'] */
|
|
13
|
+
subcommand: string[];
|
|
14
|
+
/** JSON fields confirmed available in the local gh binary */
|
|
15
|
+
jsonFields: string[];
|
|
12
16
|
}
|
|
13
|
-
export declare function
|
|
14
|
-
|
|
17
|
+
export declare function buildToolDefinitions(): Promise<ToolDefinition[]>;
|
|
18
|
+
/** Builds the gh args array for direct spawn — no shell string, no injection surface. */
|
|
19
|
+
export declare function buildGhArgs(tool: ToolDefinition, args: Record<string, unknown>): string[];
|
|
15
20
|
//# sourceMappingURL=schema.d.ts.map
|
package/dist/schema.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"schema.d.ts","sourceRoot":"","sources":["../src/schema.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"schema.d.ts","sourceRoot":"","sources":["../src/schema.ts"],"names":[],"mappings":"AAEA,MAAM,WAAW,cAAc;IAC7B,IAAI,EAAE,MAAM,CAAC;IACb,WAAW,EAAE,MAAM,CAAC;IACpB,WAAW,EAAE;QACX,IAAI,EAAE,QAAQ,CAAC;QACf,UAAU,EAAE,MAAM,CAAC,MAAM,EAAE;YAAE,IAAI,EAAE,MAAM,CAAC;YAAC,WAAW,EAAE,MAAM,CAAA;SAAE,CAAC,CAAC;QAClE,QAAQ,CAAC,EAAE,MAAM,EAAE,CAAC;KACrB,CAAC;IACF,mDAAmD;IACnD,UAAU,EAAE,MAAM,EAAE,CAAC;IACrB,6DAA6D;IAC7D,UAAU,EAAE,MAAM,EAAE,CAAC;CACtB;AAwDD,wBAAsB,oBAAoB,IAAI,OAAO,CAAC,cAAc,EAAE,CAAC,CA4CtE;AAED,yFAAyF;AACzF,wBAAgB,WAAW,CAAC,IAAI,EAAE,cAAc,EAAE,IAAI,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,GAAG,MAAM,EAAE,CAWzF"}
|
package/dist/schema.js
CHANGED
|
@@ -1,98 +1,114 @@
|
|
|
1
|
-
|
|
1
|
+
import { executeCommand } from './executor.js';
|
|
2
|
+
const FALLBACK_FIELDS = {
|
|
3
|
+
'issue list': ['number', 'title', 'state', 'labels', 'assignees', 'createdAt', 'url'],
|
|
4
|
+
'pr list': ['number', 'title', 'state', 'labels', 'assignees', 'createdAt', 'url', 'baseRefName'],
|
|
5
|
+
};
|
|
6
|
+
/**
|
|
7
|
+
* Fields known to work with the standard `repo` OAuth scope.
|
|
8
|
+
* Excludes:
|
|
9
|
+
* - Fields requiring elevated scopes (e.g. `id` requires read:project)
|
|
10
|
+
* - `body` — issue/PR body text is unbounded and causes JSON truncation
|
|
11
|
+
*/
|
|
12
|
+
const REPO_SCOPE_SAFE_FIELDS = new Set([
|
|
13
|
+
'number', 'title', 'state', 'labels', 'assignees',
|
|
14
|
+
'author', 'createdAt', 'updatedAt', 'closedAt', 'url',
|
|
15
|
+
'comments', 'milestone', 'isDraft', 'locked',
|
|
16
|
+
// PR-specific
|
|
17
|
+
'baseRefName', 'headRefName', 'headRepository', 'mergedAt', 'mergeCommit',
|
|
18
|
+
'reviewDecision', 'additions', 'deletions', 'changedFiles',
|
|
19
|
+
]);
|
|
20
|
+
/**
|
|
21
|
+
* Queries the local gh binary for the JSON fields it supports for a given
|
|
22
|
+
* subcommand. Uses an intentionally invalid field name to trigger gh's
|
|
23
|
+
* "available fields" error message, then parses the response.
|
|
24
|
+
*
|
|
25
|
+
* Falls back to a known-safe static list if detection fails.
|
|
26
|
+
*/
|
|
27
|
+
async function probeJsonFields(subcommand) {
|
|
28
|
+
const key = subcommand.join(' ');
|
|
29
|
+
try {
|
|
30
|
+
const result = await executeCommand('gh', [
|
|
31
|
+
...subcommand,
|
|
32
|
+
'--json', '__probe__',
|
|
33
|
+
'--limit', '0',
|
|
34
|
+
]);
|
|
35
|
+
const text = result.stderr;
|
|
36
|
+
// gh outputs: `run 'gh issue list --json' to see available fields`
|
|
37
|
+
// then lists them, or lists inline after a colon.
|
|
38
|
+
const match = text.match(/available fields?[:\s]+([\s\S]+?)(?:\n\n|$)/i);
|
|
39
|
+
if (match) {
|
|
40
|
+
const fields = match[1]
|
|
41
|
+
.trim()
|
|
42
|
+
.split(/[\s,]+/)
|
|
43
|
+
.map((f) => f.trim())
|
|
44
|
+
.filter((f) => /^[a-zA-Z][a-zA-Z0-9]*$/.test(f))
|
|
45
|
+
.filter((f) => REPO_SCOPE_SAFE_FIELDS.has(f)); // exclude elevated-scope fields
|
|
46
|
+
if (fields.length > 0)
|
|
47
|
+
return fields;
|
|
48
|
+
}
|
|
49
|
+
}
|
|
50
|
+
catch {
|
|
51
|
+
// gh not found or timed out — fall through to static
|
|
52
|
+
}
|
|
53
|
+
return FALLBACK_FIELDS[key] ?? [];
|
|
54
|
+
}
|
|
55
|
+
export async function buildToolDefinitions() {
|
|
56
|
+
const [issueFields, prFields] = await Promise.all([
|
|
57
|
+
probeJsonFields(['issue', 'list']),
|
|
58
|
+
probeJsonFields(['pr', 'list']),
|
|
59
|
+
]);
|
|
2
60
|
return [
|
|
3
61
|
{
|
|
4
62
|
name: 'gh_issue_list',
|
|
5
|
-
description: 'List GitHub issues
|
|
6
|
-
'
|
|
63
|
+
description: 'List GitHub issues as structured JSON. ' +
|
|
64
|
+
'Uses the local `gh` CLI and its existing authentication — no API key required.',
|
|
65
|
+
subcommand: ['issue', 'list'],
|
|
66
|
+
jsonFields: issueFields,
|
|
7
67
|
inputSchema: {
|
|
8
68
|
type: 'object',
|
|
9
69
|
properties: {
|
|
10
|
-
repo: {
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
},
|
|
15
|
-
limit: {
|
|
16
|
-
type: 'number',
|
|
17
|
-
description: 'Maximum number of issues to fetch (default: 30).',
|
|
18
|
-
},
|
|
19
|
-
state: {
|
|
20
|
-
type: 'string',
|
|
21
|
-
description: 'Filter by state: "open" (default), "closed", or "all".',
|
|
22
|
-
},
|
|
23
|
-
label: {
|
|
24
|
-
type: 'string',
|
|
25
|
-
description: 'Filter by label name.',
|
|
26
|
-
},
|
|
27
|
-
assignee: {
|
|
28
|
-
type: 'string',
|
|
29
|
-
description: 'Filter by assignee login.',
|
|
30
|
-
},
|
|
70
|
+
repo: { type: 'string', description: 'OWNER/REPO (e.g. "cli/cli"). Omit to use current directory.' },
|
|
71
|
+
limit: { type: 'number', description: 'Max results (default: 30).' },
|
|
72
|
+
state: { type: 'string', description: '"open" (default) | "closed" | "all".' },
|
|
73
|
+
label: { type: 'string', description: 'Filter by label name.' },
|
|
74
|
+
assignee: { type: 'string', description: 'Filter by assignee login.' },
|
|
31
75
|
},
|
|
32
76
|
},
|
|
33
77
|
},
|
|
34
78
|
{
|
|
35
79
|
name: 'gh_pr_list',
|
|
36
|
-
description: 'List GitHub pull requests
|
|
37
|
-
'
|
|
80
|
+
description: 'List GitHub pull requests as structured JSON. ' +
|
|
81
|
+
'Uses the local `gh` CLI and its existing authentication — no API key required.',
|
|
82
|
+
subcommand: ['pr', 'list'],
|
|
83
|
+
jsonFields: prFields,
|
|
38
84
|
inputSchema: {
|
|
39
85
|
type: 'object',
|
|
40
86
|
properties: {
|
|
41
|
-
repo: {
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
},
|
|
46
|
-
limit: {
|
|
47
|
-
type: 'number',
|
|
48
|
-
description: 'Maximum number of PRs to fetch (default: 30).',
|
|
49
|
-
},
|
|
50
|
-
state: {
|
|
51
|
-
type: 'string',
|
|
52
|
-
description: 'Filter by state: "open" (default), "closed", or "merged".',
|
|
53
|
-
},
|
|
54
|
-
base: {
|
|
55
|
-
type: 'string',
|
|
56
|
-
description: 'Filter by base branch name.',
|
|
57
|
-
},
|
|
58
|
-
assignee: {
|
|
59
|
-
type: 'string',
|
|
60
|
-
description: 'Filter by assignee login.',
|
|
61
|
-
},
|
|
87
|
+
repo: { type: 'string', description: 'OWNER/REPO (e.g. "cli/cli"). Omit to use current directory.' },
|
|
88
|
+
limit: { type: 'number', description: 'Max results (default: 30).' },
|
|
89
|
+
state: { type: 'string', description: '"open" (default) | "closed" | "merged".' },
|
|
90
|
+
base: { type: 'string', description: 'Filter by base branch.' },
|
|
91
|
+
assignee: { type: 'string', description: 'Filter by assignee login.' },
|
|
62
92
|
},
|
|
63
93
|
},
|
|
64
94
|
},
|
|
65
95
|
];
|
|
66
96
|
}
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
}
|
|
72
|
-
else if (toolName === 'gh_pr_list') {
|
|
73
|
-
parts.push('pr', 'list');
|
|
74
|
-
}
|
|
75
|
-
else {
|
|
76
|
-
throw new Error(`Unknown tool: ${toolName}`);
|
|
77
|
-
}
|
|
78
|
-
if (args['repo'] !== undefined) {
|
|
97
|
+
/** Builds the gh args array for direct spawn — no shell string, no injection surface. */
|
|
98
|
+
export function buildGhArgs(tool, args) {
|
|
99
|
+
const parts = [...tool.subcommand, '--json', tool.jsonFields.join(',')];
|
|
100
|
+
if (args['repo'] !== undefined)
|
|
79
101
|
parts.push('--repo', String(args['repo']));
|
|
80
|
-
|
|
81
|
-
if (args['limit'] !== undefined) {
|
|
102
|
+
if (args['limit'] !== undefined)
|
|
82
103
|
parts.push('--limit', String(args['limit']));
|
|
83
|
-
|
|
84
|
-
if (args['state'] !== undefined) {
|
|
104
|
+
if (args['state'] !== undefined)
|
|
85
105
|
parts.push('--state', String(args['state']));
|
|
86
|
-
|
|
87
|
-
if (toolName === 'gh_issue_list' && args['label'] !== undefined) {
|
|
106
|
+
if (args['label'] !== undefined && tool.name === 'gh_issue_list')
|
|
88
107
|
parts.push('--label', String(args['label']));
|
|
89
|
-
|
|
90
|
-
if (args['assignee'] !== undefined) {
|
|
108
|
+
if (args['assignee'] !== undefined)
|
|
91
109
|
parts.push('--assignee', String(args['assignee']));
|
|
92
|
-
|
|
93
|
-
if (toolName === 'gh_pr_list' && args['base'] !== undefined) {
|
|
110
|
+
if (args['base'] !== undefined && tool.name === 'gh_pr_list')
|
|
94
111
|
parts.push('--base', String(args['base']));
|
|
95
|
-
|
|
96
|
-
return parts.join(' ');
|
|
112
|
+
return parts;
|
|
97
113
|
}
|
|
98
114
|
//# sourceMappingURL=schema.js.map
|
package/dist/schema.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"schema.js","sourceRoot":"","sources":["../src/schema.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"schema.js","sourceRoot":"","sources":["../src/schema.ts"],"names":[],"mappings":"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"}
|
package/dist/security.d.ts
CHANGED
|
@@ -1,2 +1,11 @@
|
|
|
1
|
-
|
|
1
|
+
/**
|
|
2
|
+
* Security layer.
|
|
3
|
+
*
|
|
4
|
+
* With direct spawn(bin, args[]) there is no shell to inject into.
|
|
5
|
+
* This layer provides defense-in-depth by:
|
|
6
|
+
* 1. Whitelisting the exact subcommand paths allowed to execute.
|
|
7
|
+
* 2. Validating individual argument values for anomalous content.
|
|
8
|
+
*/
|
|
9
|
+
export declare function validateSubcommand(subcommand: string): void;
|
|
10
|
+
export declare function validateArgs(args: Record<string, unknown>): void;
|
|
2
11
|
//# sourceMappingURL=security.d.ts.map
|
package/dist/security.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"security.d.ts","sourceRoot":"","sources":["../src/security.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"security.d.ts","sourceRoot":"","sources":["../src/security.ts"],"names":[],"mappings":"AAAA;;;;;;;GAOG;AAQH,wBAAgB,kBAAkB,CAAC,UAAU,EAAE,MAAM,GAAG,IAAI,CAM3D;AAED,wBAAgB,YAAY,CAAC,IAAI,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,GAAG,IAAI,CAWhE"}
|
package/dist/security.js
CHANGED
|
@@ -1,20 +1,30 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
1
|
+
/**
|
|
2
|
+
* Security layer.
|
|
3
|
+
*
|
|
4
|
+
* With direct spawn(bin, args[]) there is no shell to inject into.
|
|
5
|
+
* This layer provides defense-in-depth by:
|
|
6
|
+
* 1. Whitelisting the exact subcommand paths allowed to execute.
|
|
7
|
+
* 2. Validating individual argument values for anomalous content.
|
|
8
|
+
*/
|
|
9
|
+
/** Only these gh subcommand paths may execute. */
|
|
10
|
+
const ALLOWED_SUBCOMMANDS = new Set([
|
|
11
|
+
'issue list',
|
|
12
|
+
'pr list',
|
|
13
|
+
]);
|
|
14
|
+
export function validateSubcommand(subcommand) {
|
|
15
|
+
if (!ALLOWED_SUBCOMMANDS.has(subcommand)) {
|
|
16
|
+
throw new Error(`Error: Subcommand "${subcommand}" is not in the read-only allow-list.`);
|
|
17
|
+
}
|
|
18
|
+
}
|
|
19
|
+
export function validateArgs(args) {
|
|
20
|
+
for (const [, val] of Object.entries(args)) {
|
|
21
|
+
if (typeof val === 'string') {
|
|
22
|
+
if (val.includes('\0')) {
|
|
23
|
+
throw new Error('Error: Null byte detected in argument value.');
|
|
24
|
+
}
|
|
25
|
+
if (val.length > 512) {
|
|
26
|
+
throw new Error('Error: Argument value exceeds maximum length (512).');
|
|
27
|
+
}
|
|
18
28
|
}
|
|
19
29
|
}
|
|
20
30
|
}
|
package/dist/security.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"security.js","sourceRoot":"","sources":["../src/security.ts"],"names":[],"mappings":"AAAA,MAAM,
|
|
1
|
+
{"version":3,"file":"security.js","sourceRoot":"","sources":["../src/security.ts"],"names":[],"mappings":"AAAA;;;;;;;GAOG;AAEH,kDAAkD;AAClD,MAAM,mBAAmB,GAAwB,IAAI,GAAG,CAAC;IACvD,YAAY;IACZ,SAAS;CACV,CAAC,CAAC;AAEH,MAAM,UAAU,kBAAkB,CAAC,UAAkB;IACnD,IAAI,CAAC,mBAAmB,CAAC,GAAG,CAAC,UAAU,CAAC,EAAE,CAAC;QACzC,MAAM,IAAI,KAAK,CACb,sBAAsB,UAAU,uCAAuC,CACxE,CAAC;IACJ,CAAC;AACH,CAAC;AAED,MAAM,UAAU,YAAY,CAAC,IAA6B;IACxD,KAAK,MAAM,CAAC,EAAE,GAAG,CAAC,IAAI,MAAM,CAAC,OAAO,CAAC,IAAI,CAAC,EAAE,CAAC;QAC3C,IAAI,OAAO,GAAG,KAAK,QAAQ,EAAE,CAAC;YAC5B,IAAI,GAAG,CAAC,QAAQ,CAAC,IAAI,CAAC,EAAE,CAAC;gBACvB,MAAM,IAAI,KAAK,CAAC,8CAA8C,CAAC,CAAC;YAClE,CAAC;YACD,IAAI,GAAG,CAAC,MAAM,GAAG,GAAG,EAAE,CAAC;gBACrB,MAAM,IAAI,KAAK,CAAC,qDAAqD,CAAC,CAAC;YACzE,CAAC;QACH,CAAC;IACH,CAAC;AACH,CAAC"}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "zero-config-cli-bridge",
|
|
3
|
-
"version": "1.0
|
|
3
|
+
"version": "1.1.0",
|
|
4
4
|
"description": "Zero Setup. Zero API Keys. Expose your local authenticated CLIs as MCP tools.",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"main": "dist/index.js",
|
|
@@ -28,6 +28,14 @@
|
|
|
28
28
|
"agent",
|
|
29
29
|
"tool"
|
|
30
30
|
],
|
|
31
|
+
"repository": {
|
|
32
|
+
"type": "git",
|
|
33
|
+
"url": "https://github.com/hatyibei/zero-config-cli-bridge"
|
|
34
|
+
},
|
|
35
|
+
"homepage": "https://github.com/hatyibei/zero-config-cli-bridge#readme",
|
|
36
|
+
"bugs": {
|
|
37
|
+
"url": "https://github.com/hatyibei/zero-config-cli-bridge/issues"
|
|
38
|
+
},
|
|
31
39
|
"license": "MIT",
|
|
32
40
|
"engines": {
|
|
33
41
|
"node": ">=20.0.0"
|