octocode-cli 1.5.1 → 1.5.3
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +28 -9
- package/out/chunks/chunk-375ZNU3A.js +317 -0
- package/out/chunks/{chunk-V64AXUWB.js → chunk-AYILFPX4.js} +1 -1
- package/out/chunks/chunk-BRHVQB64.js +10 -0
- package/out/chunks/{command-help-specs-JZXVSLZ5.js → chunk-KWJUBVXJ.js} +1 -1
- package/out/chunks/chunk-OMXWZJBJ.js +100 -0
- package/out/chunks/command-help-specs-RVJK6V6M.js +8 -0
- package/out/chunks/commands-JFDCC4Q7.js +8 -0
- package/out/chunks/{help-P7TCOYAJ.js → help-H3WGUJO7.js} +1 -1
- package/out/chunks/main-help-BUTDD4IR.js +10 -0
- package/out/chunks/{spinner-URV2OX6O.js → spinner-DXD4JQIU.js} +1 -1
- package/out/chunks/tool-command-L6PVHUNS.js +8 -0
- package/out/octocode-cli.js +1 -1
- package/package.json +2 -2
- package/skills/octocode-brainstorming/scripts/tavily-search.mjs +1 -10
- package/skills/octocode-chrome-devtools/scripts/cdp-runner.mjs +0 -2
- package/skills/octocode-chrome-devtools/scripts/cdp-sandbox.mjs +1 -5
- package/skills/octocode-chrome-devtools/scripts/cdp-template.mjs +1 -10
- package/skills/octocode-chrome-devtools/scripts/open-browser.mjs +0 -3
- package/skills/octocode-chrome-devtools/scripts/sourcemap-resolver.mjs +1 -4
- package/skills/octocode-chrome-devtools/scripts/undercover.mjs +0 -2
- package/skills/octocode-engineer/SKILL.md +7 -33
- package/skills/octocode-engineer/references/cli-reference.md +5 -11
- package/skills/octocode-engineer/references/externals.md +0 -4
- package/skills/octocode-engineer/references/quality-indicators.md +10 -50
- package/skills/octocode-engineer/references/tool-workflows.md +10 -13
- package/skills/octocode-engineer/src/analysis/dependency-summary.test.ts +2 -2
- package/skills/octocode-engineer/src/ast/metrics.test.ts +2 -2
- package/skills/octocode-engineer/src/ast/search-main.ts +2 -15
- package/skills/octocode-engineer/src/ast/search.ts +1 -7
- package/skills/octocode-engineer/src/ast/tree-sitter.test.ts +4 -4
- package/skills/octocode-engineer/src/ast/tree-sitter.ts +2 -2
- package/skills/octocode-engineer/src/collectors/chains.ts +3 -10
- package/skills/octocode-engineer/src/collectors/prototype-pollution.ts +3 -3
- package/skills/octocode-engineer/src/collectors/security.ts +3 -3
- package/skills/octocode-engineer/src/common/ensure-deps.ts +3 -20
- package/skills/octocode-engineer/src/detectors/code-quality.ts +0 -1
- package/skills/octocode-engineer/src/index.test.ts +1 -1
- package/skills/octocode-engineer/src/index.ts +1 -11
- package/skills/octocode-engineer/src/pipeline/affected.ts +2 -7
- package/skills/octocode-engineer/src/pipeline/baseline.ts +2 -8
- package/skills/octocode-engineer/src/pipeline/cache.ts +2 -2
- package/skills/octocode-engineer/src/pipeline/config-loader.test.ts +1 -2
- package/skills/octocode-engineer/src/pipeline/config-loader.ts +0 -9
- package/skills/octocode-engineer/src/pipeline/create-options.ts +2 -15
- package/skills/octocode-engineer/src/pipeline/reporters.ts +2 -12
- package/skills/octocode-engineer/src/reporting/summary-md.test.ts +2 -2
- package/skills/octocode-engineer/src/run.ts +1 -7
- package/skills/octocode-engineer/src/types/constants.ts +0 -5
- package/skills/octocode-engineer/src/types/core.ts +0 -5
- package/skills/octocode-news/eslint.config.mjs +1 -6
- package/skills/octocode-news/src/rss-core.ts +2 -4
- package/skills/octocode-research/ecosystem.config.cjs +0 -31
- package/skills/octocode-research/package.json +1 -1
- package/skills/octocode-research/scripts/server.js +272 -230
- package/skills/octocode-research/src/__tests__/integration/circuitBreaker.test.ts +0 -24
- package/skills/octocode-research/src/__tests__/integration/routes.test.ts +0 -10
- package/skills/octocode-research/src/__tests__/integration/serverLifecycle.test.ts +5 -22
- package/skills/octocode-research/src/__tests__/integration/toolsRoutes.test.ts +0 -27
- package/skills/octocode-research/src/__tests__/unit/circuitBreaker.test.ts +0 -29
- package/skills/octocode-research/src/__tests__/unit/errorHandler.test.ts +1 -12
- package/skills/octocode-research/src/__tests__/unit/httpPreprocess.test.ts +1 -9
- package/skills/octocode-research/src/__tests__/unit/logger.test.ts +0 -7
- package/skills/octocode-research/src/__tests__/unit/queryParser.test.ts +1 -7
- package/skills/octocode-research/src/__tests__/unit/responseBuilder.test.ts +0 -11
- package/skills/octocode-research/src/__tests__/unit/retry.test.ts +1 -18
- package/skills/octocode-research/src/__tests__/unit/schemas.test.ts +2 -25
- package/skills/octocode-research/src/index.ts +0 -27
- package/skills/octocode-research/src/mcpCache.ts +3 -18
- package/skills/octocode-research/src/middleware/errorHandler.ts +1 -4
- package/skills/octocode-research/src/middleware/logger.ts +1 -6
- package/skills/octocode-research/src/middleware/queryParser.ts +3 -22
- package/skills/octocode-research/src/routes/github.ts +0 -11
- package/skills/octocode-research/src/routes/local.ts +0 -12
- package/skills/octocode-research/src/routes/lsp.ts +1 -10
- package/skills/octocode-research/src/routes/package.ts +0 -2
- package/skills/octocode-research/src/routes/prompts.ts +2 -32
- package/skills/octocode-research/src/routes/tools.ts +12 -177
- package/skills/octocode-research/src/server-init.ts +0 -32
- package/skills/octocode-research/src/server.ts +8 -37
- package/skills/octocode-research/src/types/errorGuards.ts +0 -15
- package/skills/octocode-research/src/types/guards.ts +6 -27
- package/skills/octocode-research/src/types/mcp.ts +1 -8
- package/skills/octocode-research/src/types/responses.ts +0 -15
- package/skills/octocode-research/src/utils/asyncTimeout.ts +1 -63
- package/skills/octocode-research/src/utils/circuitBreaker.ts +43 -166
- package/skills/octocode-research/src/utils/colors.ts +3 -17
- package/skills/octocode-research/src/utils/errorQueue.ts +6 -28
- package/skills/octocode-research/src/utils/logger.ts +11 -93
- package/skills/octocode-research/src/utils/resilience.ts +22 -77
- package/skills/octocode-research/src/utils/responseBuilder.ts +26 -78
- package/skills/octocode-research/src/utils/responseFactory.ts +0 -7
- package/skills/octocode-research/src/utils/responseParser.ts +11 -59
- package/skills/octocode-research/src/utils/retry.ts +12 -75
- package/skills/octocode-research/src/utils/routeFactory.ts +10 -61
- package/skills/octocode-research/src/utils/url.ts +0 -5
- package/skills/octocode-research/src/validation/httpPreprocess.ts +15 -61
- package/skills/octocode-research/src/validation/schemas.ts +14 -101
- package/skills/octocode-research/src/validation/toolCallSchema.ts +5 -65
- package/skills/octocode-research/tsdown.config.ts +2 -7
- package/skills/octocode-search-skill/SKILL.md +9 -2
- package/skills/octocode-search-skill/references/discovery-surfaces.md +2 -1
- package/skills/octocode-slides/scripts/navbridge.js +1 -14
- package/skills/octocode-slides/scripts/presenter.js +2 -61
- package/skills/octocode-stats/scripts/build_dashboard.mjs +1 -19
- package/out/chunks/chunk-7476PETK.js +0 -309
- package/out/chunks/chunk-OQBJTZWK.js +0 -60
- package/out/chunks/chunk-UCZCF3BQ.js +0 -9
- package/out/chunks/commands-XBFPLHSQ.js +0 -8
- package/out/chunks/main-help-ULF5PAQY.js +0 -10
- package/out/chunks/tool-command-M6VA7P2F.js +0 -8
- package/skills/octocode-research/AGENTS.md +0 -349
|
@@ -1,88 +1,42 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Route handler factory for reducing boilerplate in route files.
|
|
3
|
-
*
|
|
4
|
-
* Abstracts the common pattern:
|
|
5
|
-
* 1. Parse and validate query params
|
|
6
|
-
* 2. Execute tool with resilience wrapper
|
|
7
|
-
* 3. Parse tool response
|
|
8
|
-
* 4. Transform data to response format
|
|
9
|
-
* 5. Send response with appropriate status
|
|
10
|
-
*
|
|
11
|
-
* @module utils/routeFactory
|
|
12
|
-
*/
|
|
13
|
-
|
|
14
1
|
import type { Request, Response, NextFunction, RequestHandler } from 'express';
|
|
15
|
-
import type { z } from 'zod
|
|
2
|
+
import type { z } from 'zod';
|
|
16
3
|
import { parseAndValidate } from '../middleware/queryParser.js';
|
|
17
4
|
import { parseToolResponse, type ParsedResponse } from './responseParser.js';
|
|
18
5
|
|
|
19
|
-
|
|
20
|
-
* Resilience wrapper type - matches the signature of withLocalResilience, withGitHubResilience, etc.
|
|
21
|
-
*/
|
|
6
|
+
|
|
22
7
|
type ResilienceWrapper = <T>(
|
|
23
8
|
fn: () => Promise<T>,
|
|
24
9
|
toolName: string
|
|
25
10
|
) => Promise<T>;
|
|
26
11
|
|
|
27
|
-
|
|
28
|
-
* Transformer function type - converts parsed tool response to final response
|
|
29
|
-
*/
|
|
12
|
+
|
|
30
13
|
type ResponseTransformer<TQuery, TResponse> = (
|
|
31
14
|
parsed: ParsedResponse,
|
|
32
15
|
queries: TQuery[]
|
|
33
16
|
) => TResponse;
|
|
34
17
|
|
|
35
|
-
|
|
36
|
-
* MCP tool function type for the route factory.
|
|
37
|
-
*
|
|
38
|
-
* Uses `any` for the params intentionally: HTTP schemas produce slightly different
|
|
39
|
-
* types than MCP tool functions expect (optional vs required fields, auto-generated id).
|
|
40
|
-
* Type safety is enforced by Zod schema validation at runtime, not by static types
|
|
41
|
-
* at this HTTP→MCP boundary.
|
|
42
|
-
*/
|
|
18
|
+
|
|
43
19
|
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
44
20
|
type McpToolFn = (params: any) => Promise<any>;
|
|
45
21
|
|
|
46
|
-
|
|
47
|
-
* Route configuration options.
|
|
48
|
-
* TQuery flows from schema validation through to response transformation.
|
|
49
|
-
* The toolFn boundary uses McpToolFn because the schema's runtime transforms
|
|
50
|
-
* (defaults, id generation) produce MCP-compatible data that TypeScript can't verify.
|
|
51
|
-
*/
|
|
22
|
+
|
|
52
23
|
interface RouteConfig<TQuery, TResponse> {
|
|
53
|
-
|
|
24
|
+
|
|
54
25
|
schema: z.ZodType<TQuery>;
|
|
55
26
|
|
|
56
|
-
|
|
27
|
+
|
|
57
28
|
toolFn: McpToolFn;
|
|
58
29
|
|
|
59
|
-
|
|
30
|
+
|
|
60
31
|
toolName: string;
|
|
61
32
|
|
|
62
|
-
|
|
33
|
+
|
|
63
34
|
resilience: ResilienceWrapper;
|
|
64
35
|
|
|
65
|
-
|
|
36
|
+
|
|
66
37
|
transform: ResponseTransformer<TQuery, TResponse>;
|
|
67
38
|
}
|
|
68
39
|
|
|
69
|
-
/**
|
|
70
|
-
* Create a route handler with standard error handling, validation, and resilience.
|
|
71
|
-
*
|
|
72
|
-
* @example
|
|
73
|
-
* ```typescript
|
|
74
|
-
* localRoutes.get('/search', createRouteHandler({
|
|
75
|
-
* schema: localSearchSchema,
|
|
76
|
-
* toolFn: localSearchCode,
|
|
77
|
-
* toolName: 'localSearchCode',
|
|
78
|
-
* resilience: withLocalResilience,
|
|
79
|
-
* transform: (parsed, queries) => {
|
|
80
|
-
* // Custom transformation logic
|
|
81
|
-
* return ResearchResponse.searchResults({ ... });
|
|
82
|
-
* },
|
|
83
|
-
* }));
|
|
84
|
-
* ```
|
|
85
|
-
*/
|
|
86
40
|
export function createRouteHandler<TQuery, TResponse>(
|
|
87
41
|
config: RouteConfig<TQuery, TResponse>
|
|
88
42
|
): RequestHandler {
|
|
@@ -90,25 +44,20 @@ export function createRouteHandler<TQuery, TResponse>(
|
|
|
90
44
|
|
|
91
45
|
return async (req: Request, res: Response, next: NextFunction): Promise<void> => {
|
|
92
46
|
try {
|
|
93
|
-
// 1. Parse and validate query params
|
|
94
47
|
const queries = parseAndValidate(
|
|
95
48
|
req.query as Record<string, unknown>,
|
|
96
49
|
schema as z.ZodType<TQuery>
|
|
97
50
|
) as TQuery[];
|
|
98
51
|
|
|
99
|
-
// 2. Execute tool with resilience wrapper
|
|
100
52
|
const rawResult = await resilience(
|
|
101
53
|
() => toolFn({ queries }),
|
|
102
54
|
toolName
|
|
103
55
|
);
|
|
104
56
|
|
|
105
|
-
// 3. Parse tool response
|
|
106
57
|
const parsed = parseToolResponse(rawResult as { content: Array<{ type: string; text: string }> });
|
|
107
58
|
|
|
108
|
-
// 4. Transform to final response format
|
|
109
59
|
const response = transform(parsed, queries);
|
|
110
60
|
|
|
111
|
-
// 5. Send response with appropriate status
|
|
112
61
|
res.status(parsed.isError ? 500 : 200).json(response);
|
|
113
62
|
} catch (error) {
|
|
114
63
|
next(error);
|
|
@@ -1,16 +1,11 @@
|
|
|
1
1
|
export function extractToolName(path: string): string {
|
|
2
|
-
// Handle /tools/call/:toolName format
|
|
3
2
|
const toolCallMatch = path.match(/^\/tools\/call\/(\w+)$/);
|
|
4
3
|
if (toolCallMatch) {
|
|
5
4
|
return toolCallMatch[1];
|
|
6
5
|
}
|
|
7
6
|
|
|
8
|
-
// Fallback: extract from path segments
|
|
9
7
|
const parts = path.split('/').filter(Boolean);
|
|
10
8
|
if (parts.length >= 2) {
|
|
11
|
-
// e.g., /tools/list -> toolsList (camelCase)
|
|
12
|
-
// or just return the second part if it looks like a tool name
|
|
13
|
-
// But typically we want the tool name if it's in the URL
|
|
14
9
|
if (parts[0] === 'tools' && parts[1] === 'call' && parts[2]) {
|
|
15
10
|
return parts[2];
|
|
16
11
|
}
|
|
@@ -1,32 +1,15 @@
|
|
|
1
|
-
|
|
2
|
-
* HTTP Query String Preprocessing Utilities
|
|
3
|
-
*
|
|
4
|
-
* HTTP query strings are always strings. These utilities convert them
|
|
5
|
-
* to proper types before Zod schema validation.
|
|
6
|
-
*
|
|
7
|
-
* @module validation/httpPreprocess
|
|
8
|
-
*/
|
|
9
|
-
|
|
10
|
-
import { z } from 'zod/v4';
|
|
1
|
+
import { z } from 'zod';
|
|
11
2
|
import path from 'path';
|
|
12
3
|
import os from 'os';
|
|
13
4
|
|
|
14
|
-
// =============================================================================
|
|
15
|
-
// Preprocessors - Convert HTTP query strings to proper types
|
|
16
|
-
// =============================================================================
|
|
17
5
|
|
|
18
|
-
/**
|
|
19
|
-
* Preprocess string to number (for query params)
|
|
20
|
-
*/
|
|
21
6
|
export const toNumber = (val: unknown): unknown => {
|
|
22
7
|
if (typeof val === 'number') return val;
|
|
23
8
|
if (typeof val === 'string' && /^\d+$/.test(val)) return parseInt(val, 10);
|
|
24
9
|
return val;
|
|
25
10
|
};
|
|
26
11
|
|
|
27
|
-
|
|
28
|
-
* Preprocess string to boolean
|
|
29
|
-
*/
|
|
12
|
+
|
|
30
13
|
export const toBoolean = (val: unknown): unknown => {
|
|
31
14
|
if (typeof val === 'boolean') return val;
|
|
32
15
|
if (val === 'true') return true;
|
|
@@ -34,9 +17,7 @@ export const toBoolean = (val: unknown): unknown => {
|
|
|
34
17
|
return val;
|
|
35
18
|
};
|
|
36
19
|
|
|
37
|
-
|
|
38
|
-
* Preprocess comma-separated string to array
|
|
39
|
-
*/
|
|
20
|
+
|
|
40
21
|
export const toArray = (val: unknown): unknown => {
|
|
41
22
|
if (Array.isArray(val)) return val;
|
|
42
23
|
if (typeof val === 'string') {
|
|
@@ -46,56 +27,38 @@ export const toArray = (val: unknown): unknown => {
|
|
|
46
27
|
return val;
|
|
47
28
|
};
|
|
48
29
|
|
|
49
|
-
// =============================================================================
|
|
50
|
-
// Reusable Schema Parts for HTTP
|
|
51
|
-
// =============================================================================
|
|
52
30
|
|
|
53
|
-
/** Numeric string that gets converted to number */
|
|
54
31
|
export const numericString = z.preprocess(toNumber, z.number().optional());
|
|
55
32
|
|
|
56
|
-
|
|
33
|
+
|
|
57
34
|
export const requiredNumber = z.preprocess(toNumber, z.number());
|
|
58
35
|
|
|
59
|
-
|
|
36
|
+
|
|
60
37
|
export const booleanString = z.preprocess(toBoolean, z.boolean().optional());
|
|
61
38
|
|
|
62
|
-
|
|
39
|
+
|
|
63
40
|
export const stringArray = z.preprocess(toArray, z.array(z.string()));
|
|
64
41
|
|
|
65
|
-
|
|
66
|
-
* URL-encoded traversal patterns to detect
|
|
67
|
-
*/
|
|
42
|
+
|
|
68
43
|
const URL_ENCODED_TRAVERSAL = [
|
|
69
|
-
'%2e%2e',
|
|
70
|
-
'%2e%2e%2f',
|
|
71
|
-
'%2e%2e%5c',
|
|
72
|
-
'%252e',
|
|
73
|
-
'%2f',
|
|
74
|
-
'%5c',
|
|
44
|
+
'%2e%2e',
|
|
45
|
+
'%2e%2e%2f',
|
|
46
|
+
'%2e%2e%5c',
|
|
47
|
+
'%252e',
|
|
48
|
+
'%2f',
|
|
49
|
+
'%5c',
|
|
75
50
|
] as const;
|
|
76
51
|
|
|
77
|
-
|
|
78
|
-
* Safe path that blocks traversal attacks.
|
|
79
|
-
*
|
|
80
|
-
* Validates:
|
|
81
|
-
* - No directory traversal (..)
|
|
82
|
-
* - No null bytes
|
|
83
|
-
* - No Windows backslashes on non-Windows systems
|
|
84
|
-
* - No URL-encoded traversal patterns
|
|
85
|
-
*/
|
|
52
|
+
|
|
86
53
|
export const safePath = z.string().refine(
|
|
87
54
|
(p) => {
|
|
88
|
-
// Check for null bytes
|
|
89
55
|
if (p.includes('\0')) return false;
|
|
90
56
|
|
|
91
|
-
// Normalize and check for traversal
|
|
92
57
|
const normalized = path.normalize(p);
|
|
93
58
|
if (normalized.includes('..')) return false;
|
|
94
59
|
|
|
95
|
-
// Reject Windows backslashes on non-Windows (can bypass checks)
|
|
96
60
|
if (os.platform() !== 'win32' && p.includes('\\')) return false;
|
|
97
61
|
|
|
98
|
-
// Check for URL-encoded traversal patterns (case-insensitive)
|
|
99
62
|
const lowerPath = p.toLowerCase();
|
|
100
63
|
if (URL_ENCODED_TRAVERSAL.some((pattern) => lowerPath.includes(pattern))) {
|
|
101
64
|
return false;
|
|
@@ -110,13 +73,7 @@ export const safePath = z.string().refine(
|
|
|
110
73
|
}
|
|
111
74
|
);
|
|
112
75
|
|
|
113
|
-
// =============================================================================
|
|
114
|
-
// Default Research Context
|
|
115
|
-
// =============================================================================
|
|
116
76
|
|
|
117
|
-
/**
|
|
118
|
-
* Default research context values for HTTP requests
|
|
119
|
-
*/
|
|
120
77
|
const RESEARCH_DEFAULTS = {
|
|
121
78
|
mainResearchGoal: 'HTTP API request',
|
|
122
79
|
researchGoal: 'Execute tool via HTTP',
|
|
@@ -125,10 +82,7 @@ const RESEARCH_DEFAULTS = {
|
|
|
125
82
|
|
|
126
83
|
let httpQueryCounter = 0;
|
|
127
84
|
|
|
128
|
-
|
|
129
|
-
* Apply research defaults and auto-generate `id`, ensuring structural compatibility
|
|
130
|
-
* with MCP tool query types (which require `id`, `mainResearchGoal`, `researchGoal`, `reasoning`).
|
|
131
|
-
*/
|
|
85
|
+
|
|
132
86
|
export function withResearchDefaults<T extends Record<string, unknown>>(
|
|
133
87
|
data: T
|
|
134
88
|
): Omit<T, 'id' | 'mainResearchGoal' | 'researchGoal' | 'reasoning'> & {
|
|
@@ -1,17 +1,5 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
3
|
-
*
|
|
4
|
-
* These schemas wrap the authoritative schemas from octocode-mcp/public
|
|
5
|
-
* with HTTP query string preprocessing (string → number/boolean/array).
|
|
6
|
-
*
|
|
7
|
-
* @module validation/schemas
|
|
8
|
-
*/
|
|
9
|
-
|
|
10
|
-
import { z } from 'zod/v4';
|
|
11
|
-
|
|
12
|
-
// =============================================================================
|
|
13
|
-
// Import HTTP preprocessing utilities
|
|
14
|
-
// =============================================================================
|
|
1
|
+
import { z } from 'zod';
|
|
2
|
+
|
|
15
3
|
import {
|
|
16
4
|
toArray,
|
|
17
5
|
safePath,
|
|
@@ -22,52 +10,37 @@ import {
|
|
|
22
10
|
withResearchDefaults,
|
|
23
11
|
} from './httpPreprocess.js';
|
|
24
12
|
|
|
25
|
-
// =============================================================================
|
|
26
|
-
// Local Route Schemas
|
|
27
|
-
// =============================================================================
|
|
28
13
|
|
|
29
|
-
/**
|
|
30
|
-
* HTTP schema for localSearchCode (ripgrep)
|
|
31
|
-
* Wraps RipgrepQuerySchema with HTTP preprocessing
|
|
32
|
-
*/
|
|
33
14
|
export const localSearchSchema = z
|
|
34
15
|
.object({
|
|
35
|
-
// Required
|
|
36
16
|
pattern: z.string().min(1, 'Pattern is required'),
|
|
37
17
|
path: safePath,
|
|
38
18
|
|
|
39
|
-
// Workflow mode preset
|
|
40
19
|
mode: z.enum(['discovery', 'paginated', 'detailed']).optional(),
|
|
41
20
|
|
|
42
|
-
// Pattern interpretation
|
|
43
21
|
fixedString: booleanString,
|
|
44
22
|
perlRegex: booleanString,
|
|
45
23
|
|
|
46
|
-
// Case sensitivity
|
|
47
24
|
smartCase: booleanString,
|
|
48
25
|
caseInsensitive: booleanString,
|
|
49
26
|
caseSensitive: booleanString,
|
|
50
27
|
|
|
51
|
-
// Match behavior
|
|
52
28
|
wholeWord: booleanString,
|
|
53
29
|
invertMatch: booleanString,
|
|
54
30
|
multiline: booleanString,
|
|
55
31
|
multilineDotall: booleanString,
|
|
56
32
|
lineRegexp: booleanString,
|
|
57
33
|
|
|
58
|
-
// File filtering
|
|
59
34
|
type: z.string().optional(),
|
|
60
35
|
include: stringArray.optional(),
|
|
61
36
|
exclude: stringArray.optional(),
|
|
62
37
|
excludeDir: stringArray.optional(),
|
|
63
38
|
binaryFiles: z.enum(['text', 'without-match', 'binary']).optional(),
|
|
64
39
|
|
|
65
|
-
// Ignore control
|
|
66
40
|
noIgnore: booleanString,
|
|
67
41
|
hidden: booleanString,
|
|
68
42
|
followSymlinks: booleanString,
|
|
69
43
|
|
|
70
|
-
// Output control
|
|
71
44
|
filesOnly: booleanString,
|
|
72
45
|
filesWithoutMatch: booleanString,
|
|
73
46
|
count: booleanString,
|
|
@@ -75,31 +48,26 @@ export const localSearchSchema = z
|
|
|
75
48
|
lineNumbers: booleanString,
|
|
76
49
|
column: booleanString,
|
|
77
50
|
|
|
78
|
-
// Context control
|
|
79
51
|
contextLines: numericString,
|
|
80
52
|
beforeContext: numericString,
|
|
81
53
|
afterContext: numericString,
|
|
82
|
-
context: numericString,
|
|
54
|
+
context: numericString,
|
|
83
55
|
matchContentLength: numericString,
|
|
84
56
|
|
|
85
|
-
// Match limiting
|
|
86
57
|
maxMatchesPerFile: numericString,
|
|
87
58
|
maxFiles: numericString,
|
|
88
|
-
maxResults: numericString,
|
|
59
|
+
maxResults: numericString,
|
|
89
60
|
|
|
90
|
-
// Pagination
|
|
91
61
|
limit: numericString,
|
|
92
62
|
filesPerPage: numericString,
|
|
93
63
|
filePageNumber: numericString,
|
|
94
64
|
matchesPerPage: numericString,
|
|
95
65
|
|
|
96
|
-
// Stats & output format
|
|
97
66
|
includeStats: booleanString,
|
|
98
67
|
includeDistribution: booleanString,
|
|
99
68
|
jsonOutput: booleanString,
|
|
100
69
|
vimgrepFormat: booleanString,
|
|
101
70
|
|
|
102
|
-
// Advanced options
|
|
103
71
|
threads: numericString,
|
|
104
72
|
mmap: booleanString,
|
|
105
73
|
noUnicode: booleanString,
|
|
@@ -111,7 +79,6 @@ export const localSearchSchema = z
|
|
|
111
79
|
debug: booleanString,
|
|
112
80
|
showFileLastModified: booleanString,
|
|
113
81
|
|
|
114
|
-
// Research context (optional for HTTP)
|
|
115
82
|
mainResearchGoal: z.string().optional(),
|
|
116
83
|
researchGoal: z.string().optional(),
|
|
117
84
|
reasoning: z.string().optional(),
|
|
@@ -127,39 +94,30 @@ export const localSearchSchema = z
|
|
|
127
94
|
return result;
|
|
128
95
|
});
|
|
129
96
|
|
|
130
|
-
|
|
131
|
-
* HTTP schema for localGetFileContent
|
|
132
|
-
* Wraps FetchContentQuerySchema with HTTP preprocessing
|
|
133
|
-
*/
|
|
97
|
+
|
|
134
98
|
export const localContentSchema = z
|
|
135
99
|
.object({
|
|
136
100
|
path: safePath,
|
|
137
101
|
|
|
138
|
-
// Line-based pagination
|
|
139
102
|
startLine: numericString,
|
|
140
103
|
endLine: numericString,
|
|
141
104
|
fullContent: booleanString,
|
|
142
105
|
|
|
143
|
-
// Pattern matching within file
|
|
144
106
|
matchString: z.string().optional(),
|
|
145
107
|
matchStringContextLines: numericString,
|
|
146
108
|
matchStringIsRegex: booleanString,
|
|
147
109
|
matchStringCaseSensitive: booleanString,
|
|
148
110
|
|
|
149
|
-
// Character-based pagination
|
|
150
111
|
charOffset: numericString,
|
|
151
112
|
charLength: numericString,
|
|
152
113
|
|
|
153
|
-
// Research context
|
|
154
114
|
mainResearchGoal: z.string().optional(),
|
|
155
115
|
researchGoal: z.string().optional(),
|
|
156
116
|
reasoning: z.string().optional(),
|
|
157
117
|
})
|
|
158
118
|
.transform(withResearchDefaults);
|
|
159
119
|
|
|
160
|
-
|
|
161
|
-
* Transform human-readable file type to MCP's Unix-style type codes
|
|
162
|
-
*/
|
|
120
|
+
|
|
163
121
|
const fileTypeTransform = (val: string | undefined) => {
|
|
164
122
|
if (!val) return undefined;
|
|
165
123
|
const typeMap: Record<string, string | undefined> = {
|
|
@@ -182,10 +140,7 @@ const fileTypeTransform = (val: string | undefined) => {
|
|
|
182
140
|
return typeMap[val] ?? val;
|
|
183
141
|
};
|
|
184
142
|
|
|
185
|
-
|
|
186
|
-
* HTTP schema for localFindFiles
|
|
187
|
-
* Wraps FindFilesQuerySchema with HTTP preprocessing
|
|
188
|
-
*/
|
|
143
|
+
|
|
189
144
|
export const localFindSchema = z
|
|
190
145
|
.object({
|
|
191
146
|
path: safePath,
|
|
@@ -239,10 +194,7 @@ export const localFindSchema = z
|
|
|
239
194
|
return result;
|
|
240
195
|
});
|
|
241
196
|
|
|
242
|
-
|
|
243
|
-
* HTTP schema for localViewStructure
|
|
244
|
-
* Wraps ViewStructureQuerySchema with HTTP preprocessing
|
|
245
|
-
*/
|
|
197
|
+
|
|
246
198
|
export const localStructureSchema = z
|
|
247
199
|
.object({
|
|
248
200
|
path: safePath,
|
|
@@ -281,14 +233,7 @@ export const localStructureSchema = z
|
|
|
281
233
|
return result;
|
|
282
234
|
});
|
|
283
235
|
|
|
284
|
-
// =============================================================================
|
|
285
|
-
// LSP Route Schemas
|
|
286
|
-
// =============================================================================
|
|
287
236
|
|
|
288
|
-
/**
|
|
289
|
-
* HTTP schema for lspGotoDefinition
|
|
290
|
-
* Wraps LSPGotoDefinitionQuerySchema with HTTP preprocessing
|
|
291
|
-
*/
|
|
292
237
|
export const lspDefinitionSchema = z
|
|
293
238
|
.object({
|
|
294
239
|
uri: safePath,
|
|
@@ -302,10 +247,7 @@ export const lspDefinitionSchema = z
|
|
|
302
247
|
})
|
|
303
248
|
.transform(withResearchDefaults);
|
|
304
249
|
|
|
305
|
-
|
|
306
|
-
* HTTP schema for lspFindReferences
|
|
307
|
-
* Wraps LSPFindReferencesQuerySchema with HTTP preprocessing
|
|
308
|
-
*/
|
|
250
|
+
|
|
309
251
|
export const lspReferencesSchema = z
|
|
310
252
|
.object({
|
|
311
253
|
uri: safePath,
|
|
@@ -322,10 +264,7 @@ export const lspReferencesSchema = z
|
|
|
322
264
|
})
|
|
323
265
|
.transform(withResearchDefaults);
|
|
324
266
|
|
|
325
|
-
|
|
326
|
-
* HTTP schema for lspCallHierarchy
|
|
327
|
-
* Wraps LSPCallHierarchyQuerySchema with HTTP preprocessing
|
|
328
|
-
*/
|
|
267
|
+
|
|
329
268
|
export const lspCallsSchema = z
|
|
330
269
|
.object({
|
|
331
270
|
uri: safePath,
|
|
@@ -345,14 +284,7 @@ export const lspCallsSchema = z
|
|
|
345
284
|
})
|
|
346
285
|
.transform(withResearchDefaults);
|
|
347
286
|
|
|
348
|
-
// =============================================================================
|
|
349
|
-
// GitHub Route Schemas
|
|
350
|
-
// =============================================================================
|
|
351
287
|
|
|
352
|
-
/**
|
|
353
|
-
* HTTP schema for githubSearchCode
|
|
354
|
-
* Wraps GitHubCodeSearchQuerySchema with HTTP preprocessing
|
|
355
|
-
*/
|
|
356
288
|
export const githubSearchSchema = z
|
|
357
289
|
.object({
|
|
358
290
|
keywordsToSearch: stringArray,
|
|
@@ -370,10 +302,7 @@ export const githubSearchSchema = z
|
|
|
370
302
|
})
|
|
371
303
|
.transform(withResearchDefaults);
|
|
372
304
|
|
|
373
|
-
|
|
374
|
-
* HTTP schema for githubGetFileContent
|
|
375
|
-
* Wraps FileContentQuerySchema with HTTP preprocessing
|
|
376
|
-
*/
|
|
305
|
+
|
|
377
306
|
export const githubContentSchema = z
|
|
378
307
|
.object({
|
|
379
308
|
owner: z.string().min(1, 'Owner is required'),
|
|
@@ -393,10 +322,7 @@ export const githubContentSchema = z
|
|
|
393
322
|
})
|
|
394
323
|
.transform(withResearchDefaults);
|
|
395
324
|
|
|
396
|
-
|
|
397
|
-
* HTTP schema for githubSearchRepositories
|
|
398
|
-
* Wraps GitHubReposSearchSingleQuerySchema with HTTP preprocessing
|
|
399
|
-
*/
|
|
325
|
+
|
|
400
326
|
export const githubReposSchema = z
|
|
401
327
|
.object({
|
|
402
328
|
keywordsToSearch: stringArray.optional(),
|
|
@@ -425,10 +351,7 @@ export const githubReposSchema = z
|
|
|
425
351
|
)
|
|
426
352
|
.transform(withResearchDefaults);
|
|
427
353
|
|
|
428
|
-
|
|
429
|
-
* HTTP schema for githubViewRepoStructure
|
|
430
|
-
* Wraps GitHubViewRepoStructureQuerySchema with HTTP preprocessing
|
|
431
|
-
*/
|
|
354
|
+
|
|
432
355
|
export const githubStructureSchema = z
|
|
433
356
|
.object({
|
|
434
357
|
owner: z.string().min(1, 'Owner is required'),
|
|
@@ -444,10 +367,7 @@ export const githubStructureSchema = z
|
|
|
444
367
|
})
|
|
445
368
|
.transform(withResearchDefaults);
|
|
446
369
|
|
|
447
|
-
|
|
448
|
-
* HTTP schema for githubSearchPullRequests
|
|
449
|
-
* Wraps GitHubPullRequestSearchQuerySchema with HTTP preprocessing
|
|
450
|
-
*/
|
|
370
|
+
|
|
451
371
|
export const githubPRsSchema = z
|
|
452
372
|
.object({
|
|
453
373
|
query: z.string().optional(),
|
|
@@ -492,14 +412,7 @@ export const githubPRsSchema = z
|
|
|
492
412
|
})
|
|
493
413
|
.transform(withResearchDefaults);
|
|
494
414
|
|
|
495
|
-
// =============================================================================
|
|
496
|
-
// Package Route Schemas
|
|
497
|
-
// =============================================================================
|
|
498
415
|
|
|
499
|
-
/**
|
|
500
|
-
* HTTP schema for packageSearch
|
|
501
|
-
* Wraps PackageSearchQuerySchema with HTTP preprocessing
|
|
502
|
-
*/
|
|
503
416
|
export const packageSearchSchema = z
|
|
504
417
|
.object({
|
|
505
418
|
name: z.string().min(1, 'Package name is required'),
|
|
@@ -1,40 +1,15 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
* Centralizes validation logic to avoid duplication across routes.
|
|
5
|
-
*
|
|
6
|
-
* @module validation/toolCallSchema
|
|
7
|
-
*/
|
|
8
|
-
|
|
9
|
-
import { z } from 'zod/v4';
|
|
10
|
-
|
|
11
|
-
// =============================================================================
|
|
12
|
-
// Constants
|
|
13
|
-
// =============================================================================
|
|
14
|
-
|
|
15
|
-
/**
|
|
16
|
-
* Maximum number of queries per tool call.
|
|
17
|
-
* Limits parallel execution to prevent resource exhaustion.
|
|
18
|
-
*/
|
|
1
|
+
import { z } from 'zod';
|
|
2
|
+
|
|
3
|
+
|
|
19
4
|
export const MAX_QUERIES = 3;
|
|
20
5
|
|
|
21
|
-
// =============================================================================
|
|
22
|
-
// Schemas
|
|
23
|
-
// =============================================================================
|
|
24
6
|
|
|
25
|
-
/**
|
|
26
|
-
* Schema for individual query objects.
|
|
27
|
-
* Each query must be a non-empty object with arbitrary key-value pairs.
|
|
28
|
-
*/
|
|
29
7
|
const querySchema = z.record(z.string(), z.unknown()).refine(
|
|
30
8
|
(obj) => Object.keys(obj).length > 0,
|
|
31
9
|
{ message: 'Query object cannot be empty' }
|
|
32
10
|
);
|
|
33
11
|
|
|
34
|
-
|
|
35
|
-
* Schema for tool call request body.
|
|
36
|
-
* Requires a queries array with 1-3 items.
|
|
37
|
-
*/
|
|
12
|
+
|
|
38
13
|
const toolCallBodySchema = z.object({
|
|
39
14
|
queries: z
|
|
40
15
|
.array(querySchema)
|
|
@@ -42,18 +17,10 @@ const toolCallBodySchema = z.object({
|
|
|
42
17
|
.max(MAX_QUERIES, `Maximum ${MAX_QUERIES} queries per request`),
|
|
43
18
|
});
|
|
44
19
|
|
|
45
|
-
|
|
46
|
-
* Inferred type from the schema
|
|
47
|
-
*/
|
|
20
|
+
|
|
48
21
|
type ToolCallBody = z.infer<typeof toolCallBodySchema>;
|
|
49
22
|
|
|
50
|
-
// =============================================================================
|
|
51
|
-
// Validation Function
|
|
52
|
-
// =============================================================================
|
|
53
23
|
|
|
54
|
-
/**
|
|
55
|
-
* Validation result type
|
|
56
|
-
*/
|
|
57
24
|
interface ValidationResult<T> {
|
|
58
25
|
success: boolean;
|
|
59
26
|
data?: T;
|
|
@@ -63,25 +30,6 @@ interface ValidationResult<T> {
|
|
|
63
30
|
};
|
|
64
31
|
}
|
|
65
32
|
|
|
66
|
-
/**
|
|
67
|
-
* Validate tool call body against schema.
|
|
68
|
-
*
|
|
69
|
-
* @param body - Request body to validate
|
|
70
|
-
* @returns Validation result with data or error details
|
|
71
|
-
*
|
|
72
|
-
* @example
|
|
73
|
-
* ```typescript
|
|
74
|
-
* const result = validateToolCallBody(req.body);
|
|
75
|
-
* if (!result.success) {
|
|
76
|
-
* res.status(400).json({
|
|
77
|
-
* success: false,
|
|
78
|
-
* hints: [result.error.message, ...result.error.details.map(d => d.message)]
|
|
79
|
-
* });
|
|
80
|
-
* return;
|
|
81
|
-
* }
|
|
82
|
-
* const { queries } = result.data;
|
|
83
|
-
* ```
|
|
84
|
-
*/
|
|
85
33
|
export function validateToolCallBody(body: unknown): ValidationResult<ToolCallBody> {
|
|
86
34
|
const result = toolCallBodySchema.safeParse(body);
|
|
87
35
|
|
|
@@ -104,20 +52,12 @@ export function validateToolCallBody(body: unknown): ValidationResult<ToolCallBo
|
|
|
104
52
|
};
|
|
105
53
|
}
|
|
106
54
|
|
|
107
|
-
/**
|
|
108
|
-
* Generate user-friendly hints for validation errors.
|
|
109
|
-
*
|
|
110
|
-
* @param toolName - Name of the tool being called
|
|
111
|
-
* @param error - Validation error details
|
|
112
|
-
* @returns Array of hint strings for the user
|
|
113
|
-
*/
|
|
114
55
|
export function getValidationHints(
|
|
115
56
|
toolName: string,
|
|
116
57
|
error: { message: string; details: z.core.$ZodIssue[] }
|
|
117
58
|
): string[] {
|
|
118
59
|
const hints = [error.message];
|
|
119
60
|
|
|
120
|
-
// Add specific hints based on error type
|
|
121
61
|
const hasQueriesError = error.details.some(
|
|
122
62
|
(d) => d.path.includes('queries') || d.message.includes('queries')
|
|
123
63
|
);
|