@cognium/mcp-server 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.
- package/CHANGELOG.md +39 -0
- package/LICENSE +21 -0
- package/README.md +107 -0
- package/dist/cache.d.ts +46 -0
- package/dist/cache.d.ts.map +1 -0
- package/dist/cache.js +106 -0
- package/dist/cache.js.map +1 -0
- package/dist/index.d.ts +12 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +24 -0
- package/dist/index.js.map +1 -0
- package/dist/resources/catalogs.d.ts +63 -0
- package/dist/resources/catalogs.d.ts.map +1 -0
- package/dist/resources/catalogs.js +92 -0
- package/dist/resources/catalogs.js.map +1 -0
- package/dist/resources/index.d.ts +13 -0
- package/dist/resources/index.d.ts.map +1 -0
- package/dist/resources/index.js +94 -0
- package/dist/resources/index.js.map +1 -0
- package/dist/resources/schema.d.ts +81 -0
- package/dist/resources/schema.d.ts.map +1 -0
- package/dist/resources/schema.js +63 -0
- package/dist/resources/schema.js.map +1 -0
- package/dist/server.d.ts +12 -0
- package/dist/server.d.ts.map +1 -0
- package/dist/server.js +41 -0
- package/dist/server.js.map +1 -0
- package/dist/tools/attack-surface-summary.d.ts +24 -0
- package/dist/tools/attack-surface-summary.d.ts.map +1 -0
- package/dist/tools/attack-surface-summary.js +116 -0
- package/dist/tools/attack-surface-summary.js.map +1 -0
- package/dist/tools/check-sanitizer.d.ts +29 -0
- package/dist/tools/check-sanitizer.d.ts.map +1 -0
- package/dist/tools/check-sanitizer.js +82 -0
- package/dist/tools/check-sanitizer.js.map +1 -0
- package/dist/tools/describe-sink.d.ts +22 -0
- package/dist/tools/describe-sink.d.ts.map +1 -0
- package/dist/tools/describe-sink.js +47 -0
- package/dist/tools/describe-sink.js.map +1 -0
- package/dist/tools/describe-source.d.ts +27 -0
- package/dist/tools/describe-source.d.ts.map +1 -0
- package/dist/tools/describe-source.js +64 -0
- package/dist/tools/describe-source.js.map +1 -0
- package/dist/tools/explain-finding.d.ts +23 -0
- package/dist/tools/explain-finding.d.ts.map +1 -0
- package/dist/tools/explain-finding.js +65 -0
- package/dist/tools/explain-finding.js.map +1 -0
- package/dist/tools/find-similar.d.ts +34 -0
- package/dist/tools/find-similar.d.ts.map +1 -0
- package/dist/tools/find-similar.js +107 -0
- package/dist/tools/find-similar.js.map +1 -0
- package/dist/tools/list-entry-points.d.ts +22 -0
- package/dist/tools/list-entry-points.d.ts.map +1 -0
- package/dist/tools/list-entry-points.js +71 -0
- package/dist/tools/list-entry-points.js.map +1 -0
- package/dist/tools/list-reachable-sinks.d.ts +33 -0
- package/dist/tools/list-reachable-sinks.d.ts.map +1 -0
- package/dist/tools/list-reachable-sinks.js +116 -0
- package/dist/tools/list-reachable-sinks.js.map +1 -0
- package/dist/tools/refresh.d.ts +21 -0
- package/dist/tools/refresh.d.ts.map +1 -0
- package/dist/tools/refresh.js +39 -0
- package/dist/tools/refresh.js.map +1 -0
- package/dist/tools/scan.d.ts +42 -0
- package/dist/tools/scan.d.ts.map +1 -0
- package/dist/tools/scan.js +197 -0
- package/dist/tools/scan.js.map +1 -0
- package/dist/tools/taint-paths.d.ts +31 -0
- package/dist/tools/taint-paths.d.ts.map +1 -0
- package/dist/tools/taint-paths.js +55 -0
- package/dist/tools/taint-paths.js.map +1 -0
- package/dist/tools/types.d.ts +22 -0
- package/dist/tools/types.d.ts.map +1 -0
- package/dist/tools/types.js +17 -0
- package/dist/tools/types.js.map +1 -0
- package/dist/util/files.d.ts +33 -0
- package/dist/util/files.d.ts.map +1 -0
- package/dist/util/files.js +184 -0
- package/dist/util/files.js.map +1 -0
- package/dist/util/serialize.d.ts +29 -0
- package/dist/util/serialize.d.ts.map +1 -0
- package/dist/util/serialize.js +42 -0
- package/dist/util/serialize.js.map +1 -0
- package/dist/util/wasm.d.ts +9 -0
- package/dist/util/wasm.d.ts.map +1 -0
- package/dist/util/wasm.js +37 -0
- package/dist/util/wasm.js.map +1 -0
- package/package.json +75 -0
|
@@ -0,0 +1,64 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* `describe_source` tool — enumerate taint-source patterns known to
|
|
3
|
+
* circle-ir for a given source category (e.g. `http_param`, `http_header`,
|
|
4
|
+
* `db_result`, `env`, `file`).
|
|
5
|
+
*
|
|
6
|
+
* Used by an LLM to answer "where would attacker-controlled data enter
|
|
7
|
+
* this codebase from `http_body`?" without guessing framework APIs.
|
|
8
|
+
*/
|
|
9
|
+
import { z } from 'zod';
|
|
10
|
+
import { textResult, errorResult } from './types.js';
|
|
11
|
+
import { loadSourceCatalog } from '../resources/catalogs.js';
|
|
12
|
+
export const describeSourceInputShape = {
|
|
13
|
+
source_type: z.string()
|
|
14
|
+
.describe('Source category, e.g. "http_param", "http_header", "http_body", "http_cookie", "db_result", "env", "file".'),
|
|
15
|
+
language: z.enum(['java', 'javascript', 'typescript', 'python', 'go', 'rust', 'bash', 'html'])
|
|
16
|
+
.optional()
|
|
17
|
+
.describe('Restrict patterns to this language.'),
|
|
18
|
+
};
|
|
19
|
+
export const describeSourceConfig = {
|
|
20
|
+
title: 'Describe taint source category',
|
|
21
|
+
description: 'Return every taint-source pattern (method / class / property / annotation) that circle-ir treats as ' +
|
|
22
|
+
'a source of the given category. Use when the LLM needs to know "which framework APIs count as an ' +
|
|
23
|
+
'HTTP body source?" or "what constitutes an env-var source?"',
|
|
24
|
+
inputSchema: describeSourceInputShape,
|
|
25
|
+
};
|
|
26
|
+
export function makeDescribeSourceHandler(_ctx) {
|
|
27
|
+
return async (args) => {
|
|
28
|
+
const catalog = loadSourceCatalog();
|
|
29
|
+
const matches = catalog.filter((s) => {
|
|
30
|
+
if (s.type !== args.source_type)
|
|
31
|
+
return false;
|
|
32
|
+
if (args.language && s.languages && !s.languages.includes(args.language))
|
|
33
|
+
return false;
|
|
34
|
+
return true;
|
|
35
|
+
});
|
|
36
|
+
if (matches.length === 0) {
|
|
37
|
+
const known = [...new Set(catalog.map((s) => s.type))].sort();
|
|
38
|
+
return errorResult(`No source patterns for source_type "${args.source_type}"` +
|
|
39
|
+
(args.language ? ` in language "${args.language}"` : '') +
|
|
40
|
+
`. Known source types: ${known.join(', ')}`);
|
|
41
|
+
}
|
|
42
|
+
return textResult({
|
|
43
|
+
source_type: args.source_type,
|
|
44
|
+
language: args.language ?? 'any',
|
|
45
|
+
totalPatterns: matches.length,
|
|
46
|
+
patterns: matches.slice(0, 200).map((s) => ({
|
|
47
|
+
method: s.method,
|
|
48
|
+
class: s.class,
|
|
49
|
+
property: s.property,
|
|
50
|
+
object: s.object,
|
|
51
|
+
annotation: s.annotation,
|
|
52
|
+
methodAnnotation: s.methodAnnotation,
|
|
53
|
+
severity: s.severity,
|
|
54
|
+
returnTainted: s.returnTainted,
|
|
55
|
+
paramTainted: s.paramTainted,
|
|
56
|
+
propertyTainted: s.propertyTainted,
|
|
57
|
+
languages: s.languages,
|
|
58
|
+
note: s.note,
|
|
59
|
+
})),
|
|
60
|
+
truncated: matches.length > 200,
|
|
61
|
+
});
|
|
62
|
+
};
|
|
63
|
+
}
|
|
64
|
+
//# sourceMappingURL=describe-source.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"describe-source.js","sourceRoot":"","sources":["../../src/tools/describe-source.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* `explain_finding` tool — enrich a single SastFinding with CWE metadata,
|
|
3
|
+
* remediation guidance, and sanitizer alternatives.
|
|
4
|
+
*/
|
|
5
|
+
import { z } from 'zod';
|
|
6
|
+
import type { ToolContext, ToolResult } from './types.js';
|
|
7
|
+
export declare const explainFindingInputShape: {
|
|
8
|
+
readonly project_root: z.ZodString;
|
|
9
|
+
readonly finding_id: z.ZodString;
|
|
10
|
+
};
|
|
11
|
+
export declare const explainFindingConfig: {
|
|
12
|
+
readonly title: "Explain finding";
|
|
13
|
+
readonly description: string;
|
|
14
|
+
readonly inputSchema: {
|
|
15
|
+
readonly project_root: z.ZodString;
|
|
16
|
+
readonly finding_id: z.ZodString;
|
|
17
|
+
};
|
|
18
|
+
};
|
|
19
|
+
export declare function makeExplainFindingHandler(ctx: ToolContext): (args: {
|
|
20
|
+
project_root: string;
|
|
21
|
+
finding_id: string;
|
|
22
|
+
}) => Promise<ToolResult>;
|
|
23
|
+
//# sourceMappingURL=explain-finding.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"explain-finding.d.ts","sourceRoot":"","sources":["../../src/tools/explain-finding.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAEH,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAC;AAGxB,OAAO,KAAK,EAAE,WAAW,EAAE,UAAU,EAAE,MAAM,YAAY,CAAC;AAI1D,eAAO,MAAM,wBAAwB;;;CAG3B,CAAC;AAEX,eAAO,MAAM,oBAAoB;;;;;;;CAOvB,CAAC;AAEX,wBAAgB,yBAAyB,CAAC,GAAG,EAAE,WAAW,IAC1C,MAAM;IAAE,YAAY,EAAE,MAAM,CAAC;IAAC,UAAU,EAAE,MAAM,CAAA;CAAE,KAAG,OAAO,CAAC,UAAU,CAAC,CAoCvF"}
|
|
@@ -0,0 +1,65 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* `explain_finding` tool — enrich a single SastFinding with CWE metadata,
|
|
3
|
+
* remediation guidance, and sanitizer alternatives.
|
|
4
|
+
*/
|
|
5
|
+
import { z } from 'zod';
|
|
6
|
+
import { RULE_DEFINITIONS } from 'circle-ir';
|
|
7
|
+
import { resolve } from 'path';
|
|
8
|
+
import { textResult, errorResult } from './types.js';
|
|
9
|
+
import { truncateString } from '../util/serialize.js';
|
|
10
|
+
export const explainFindingInputShape = {
|
|
11
|
+
project_root: z.string().describe('Absolute path to the project root that was previously scanned.'),
|
|
12
|
+
finding_id: z.string().describe('The `id` field of a SastFinding returned by `scan`.'),
|
|
13
|
+
};
|
|
14
|
+
export const explainFindingConfig = {
|
|
15
|
+
title: 'Explain finding',
|
|
16
|
+
description: 'Return full context for a single SastFinding: CWE metadata (name, short/full description, remediation, ' +
|
|
17
|
+
'CVSS-like score), source-code snippet, and — if the finding is a taint sink — the list of sanitizers ' +
|
|
18
|
+
'that would neutralize it. Use before proposing a fix so the LLM cites authoritative rule content.',
|
|
19
|
+
inputSchema: explainFindingInputShape,
|
|
20
|
+
};
|
|
21
|
+
export function makeExplainFindingHandler(ctx) {
|
|
22
|
+
return async (args) => {
|
|
23
|
+
const projectRoot = resolve(args.project_root);
|
|
24
|
+
// Try every cached option-set for this root.
|
|
25
|
+
// We don't know which option-set was used at scan time, so we scan them all.
|
|
26
|
+
for (const opts of enumerateCachedOptionSets(ctx, projectRoot)) {
|
|
27
|
+
const { analysis } = await ctx.cache.getOrCompute(projectRoot, opts);
|
|
28
|
+
for (const fa of analysis.files) {
|
|
29
|
+
for (const f of fa.analysis.findings ?? []) {
|
|
30
|
+
if (f.id !== args.finding_id)
|
|
31
|
+
continue;
|
|
32
|
+
const rule = f.rule_id in RULE_DEFINITIONS
|
|
33
|
+
? RULE_DEFINITIONS[f.rule_id]
|
|
34
|
+
: undefined;
|
|
35
|
+
return textResult({
|
|
36
|
+
finding: {
|
|
37
|
+
...f,
|
|
38
|
+
message: truncateString(f.message),
|
|
39
|
+
snippet: truncateString(f.snippet),
|
|
40
|
+
fix: truncateString(f.fix),
|
|
41
|
+
},
|
|
42
|
+
rule: rule
|
|
43
|
+
? {
|
|
44
|
+
name: rule.name,
|
|
45
|
+
shortDescription: rule.shortDescription,
|
|
46
|
+
fullDescription: rule.fullDescription,
|
|
47
|
+
remediation: rule.remediation,
|
|
48
|
+
cvssScore: rule.cvssScore,
|
|
49
|
+
severityLevel: rule.severityLevel,
|
|
50
|
+
cwe: rule.cwe,
|
|
51
|
+
}
|
|
52
|
+
: { note: 'No RULE_DEFINITIONS entry — this rule_id is a quality/reliability pass, not a taint sink. Consult PASSES.md via `cognium://passes` resource for canonical metadata.' },
|
|
53
|
+
});
|
|
54
|
+
}
|
|
55
|
+
}
|
|
56
|
+
}
|
|
57
|
+
return errorResult(`Finding not found: ${args.finding_id}. Call \`scan\` first (or with the same option-set that produced the id).`);
|
|
58
|
+
};
|
|
59
|
+
}
|
|
60
|
+
function enumerateCachedOptionSets(_ctx, _projectRoot) {
|
|
61
|
+
// MVP: only try the default option-set. If none is cached, the caller
|
|
62
|
+
// is instructed to run `scan` first.
|
|
63
|
+
return [{}];
|
|
64
|
+
}
|
|
65
|
+
//# sourceMappingURL=explain-finding.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"explain-finding.js","sourceRoot":"","sources":["../../src/tools/explain-finding.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAEH,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAC;AACxB,OAAO,EAAE,gBAAgB,EAAiB,MAAM,WAAW,CAAC;AAC5D,OAAO,EAAE,OAAO,EAAE,MAAM,MAAM,CAAC;AAE/B,OAAO,EAAE,UAAU,EAAE,WAAW,EAAE,MAAM,YAAY,CAAC;AACrD,OAAO,EAAE,cAAc,EAAE,MAAM,sBAAsB,CAAC;AAEtD,MAAM,CAAC,MAAM,wBAAwB,GAAG;IACtC,YAAY,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,QAAQ,CAAC,gEAAgE,CAAC;IACnG,UAAU,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,QAAQ,CAAC,qDAAqD,CAAC;CAC9E,CAAC;AAEX,MAAM,CAAC,MAAM,oBAAoB,GAAG;IAClC,KAAK,EAAE,iBAAiB;IACxB,WAAW,EACT,yGAAyG;QACzG,uGAAuG;QACvG,mGAAmG;IACrG,WAAW,EAAE,wBAAwB;CAC7B,CAAC;AAEX,MAAM,UAAU,yBAAyB,CAAC,GAAgB;IACxD,OAAO,KAAK,EAAE,IAAkD,EAAuB,EAAE;QACvF,MAAM,WAAW,GAAG,OAAO,CAAC,IAAI,CAAC,YAAY,CAAC,CAAC;QAC/C,6CAA6C;QAC7C,6EAA6E;QAC7E,KAAK,MAAM,IAAI,IAAI,yBAAyB,CAAC,GAAG,EAAE,WAAW,CAAC,EAAE,CAAC;YAC/D,MAAM,EAAE,QAAQ,EAAE,GAAG,MAAM,GAAG,CAAC,KAAK,CAAC,YAAY,CAAC,WAAW,EAAE,IAAI,CAAC,CAAC;YACrE,KAAK,MAAM,EAAE,IAAI,QAAQ,CAAC,KAAK,EAAE,CAAC;gBAChC,KAAK,MAAM,CAAC,IAAI,EAAE,CAAC,QAAQ,CAAC,QAAQ,IAAI,EAAE,EAAE,CAAC;oBAC3C,IAAI,CAAC,CAAC,EAAE,KAAK,IAAI,CAAC,UAAU;wBAAE,SAAS;oBACvC,MAAM,IAAI,GAAG,CAAC,CAAC,OAAO,IAAI,gBAAgB;wBACxC,CAAC,CAAC,gBAAgB,CAAC,CAAC,CAAC,OAAmB,CAAC;wBACzC,CAAC,CAAC,SAAS,CAAC;oBACd,OAAO,UAAU,CAAC;wBAChB,OAAO,EAAE;4BACP,GAAG,CAAC;4BACJ,OAAO,EAAE,cAAc,CAAC,CAAC,CAAC,OAAO,CAAC;4BAClC,OAAO,EAAE,cAAc,CAAC,CAAC,CAAC,OAAO,CAAC;4BAClC,GAAG,EAAE,cAAc,CAAC,CAAC,CAAC,GAAG,CAAC;yBAC3B;wBACD,IAAI,EAAE,IAAI;4BACR,CAAC,CAAC;gCACA,IAAI,EAAE,IAAI,CAAC,IAAI;gCACf,gBAAgB,EAAE,IAAI,CAAC,gBAAgB;gCACvC,eAAe,EAAE,IAAI,CAAC,eAAe;gCACrC,WAAW,EAAE,IAAI,CAAC,WAAW;gCAC7B,SAAS,EAAE,IAAI,CAAC,SAAS;gCACzB,aAAa,EAAE,IAAI,CAAC,aAAa;gCACjC,GAAG,EAAE,IAAI,CAAC,GAAG;6BACd;4BACD,CAAC,CAAC,EAAE,IAAI,EAAE,qKAAqK,EAAE;qBACpL,CAAC,CAAC;gBACL,CAAC;YACH,CAAC;QACH,CAAC;QACD,OAAO,WAAW,CAAC,sBAAsB,IAAI,CAAC,UAAU,2EAA2E,CAAC,CAAC;IACvI,CAAC,CAAC;AACJ,CAAC;AAED,SAAS,yBAAyB,CAAC,IAAiB,EAAE,YAAoB;IACxE,sEAAsE;IACtE,qCAAqC;IACrC,OAAO,CAAC,EAAE,CAAC,CAAC;AACd,CAAC"}
|
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* `find_similar` tool — given a finding id (from a prior `scan`), return
|
|
3
|
+
* every other finding in the same project that shares the same
|
|
4
|
+
* `rule_id` + `sink_type` (or matches by structural similarity of the
|
|
5
|
+
* source→sink pair).
|
|
6
|
+
*
|
|
7
|
+
* Answers "did I miss this pattern anywhere else in the code?" — a
|
|
8
|
+
* common LLM follow-up after triaging one issue.
|
|
9
|
+
*/
|
|
10
|
+
import { z } from 'zod';
|
|
11
|
+
import type { ToolContext, ToolResult } from './types.js';
|
|
12
|
+
export declare const findSimilarInputShape: {
|
|
13
|
+
readonly project_root: z.ZodString;
|
|
14
|
+
readonly finding_id: z.ZodString;
|
|
15
|
+
readonly match_by: z.ZodOptional<z.ZodEnum<["rule_and_sink", "rule", "sink"]>>;
|
|
16
|
+
readonly max_results: z.ZodOptional<z.ZodNumber>;
|
|
17
|
+
};
|
|
18
|
+
export declare const findSimilarConfig: {
|
|
19
|
+
readonly title: "Find structurally similar findings";
|
|
20
|
+
readonly description: string;
|
|
21
|
+
readonly inputSchema: {
|
|
22
|
+
readonly project_root: z.ZodString;
|
|
23
|
+
readonly finding_id: z.ZodString;
|
|
24
|
+
readonly match_by: z.ZodOptional<z.ZodEnum<["rule_and_sink", "rule", "sink"]>>;
|
|
25
|
+
readonly max_results: z.ZodOptional<z.ZodNumber>;
|
|
26
|
+
};
|
|
27
|
+
};
|
|
28
|
+
export declare function makeFindSimilarHandler(ctx: ToolContext): (args: {
|
|
29
|
+
project_root: string;
|
|
30
|
+
finding_id: string;
|
|
31
|
+
match_by?: "rule_and_sink" | "rule" | "sink";
|
|
32
|
+
max_results?: number;
|
|
33
|
+
}) => Promise<ToolResult>;
|
|
34
|
+
//# sourceMappingURL=find-similar.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"find-similar.d.ts","sourceRoot":"","sources":["../../src/tools/find-similar.ts"],"names":[],"mappings":"AAAA;;;;;;;;GAQG;AAEH,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAC;AAExB,OAAO,KAAK,EAAE,WAAW,EAAE,UAAU,EAAE,MAAM,YAAY,CAAC;AAI1D,eAAO,MAAM,qBAAqB;;;;;CAQxB,CAAC;AAEX,eAAO,MAAM,iBAAiB;;;;;;;;;CAOpB,CAAC;AAEX,wBAAgB,sBAAsB,CAAC,GAAG,EAAE,WAAW,IACvC,MAAM;IAClB,YAAY,EAAE,MAAM,CAAC;IACrB,UAAU,EAAE,MAAM,CAAC;IACnB,QAAQ,CAAC,EAAE,eAAe,GAAG,MAAM,GAAG,MAAM,CAAC;IAC7C,WAAW,CAAC,EAAE,MAAM,CAAC;CACtB,KAAG,OAAO,CAAC,UAAU,CAAC,CA8ExB"}
|
|
@@ -0,0 +1,107 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* `find_similar` tool — given a finding id (from a prior `scan`), return
|
|
3
|
+
* every other finding in the same project that shares the same
|
|
4
|
+
* `rule_id` + `sink_type` (or matches by structural similarity of the
|
|
5
|
+
* source→sink pair).
|
|
6
|
+
*
|
|
7
|
+
* Answers "did I miss this pattern anywhere else in the code?" — a
|
|
8
|
+
* common LLM follow-up after triaging one issue.
|
|
9
|
+
*/
|
|
10
|
+
import { z } from 'zod';
|
|
11
|
+
import { resolve } from 'path';
|
|
12
|
+
import { textResult, errorResult } from './types.js';
|
|
13
|
+
import { truncateArray, truncateString, MAX_FINDINGS } from '../util/serialize.js';
|
|
14
|
+
export const findSimilarInputShape = {
|
|
15
|
+
project_root: z.string().describe('Absolute path to the project root.'),
|
|
16
|
+
finding_id: z.string()
|
|
17
|
+
.describe('Anchor finding id (from `scan` output). Similar findings are relative to this one.'),
|
|
18
|
+
match_by: z.enum(['rule_and_sink', 'rule', 'sink']).optional()
|
|
19
|
+
.describe('Similarity axis: `rule_and_sink` (default) matches rule_id + taint sink_type, `rule` matches rule_id only, `sink` matches sink_type only.'),
|
|
20
|
+
max_results: z.number().int().min(1).max(200).optional()
|
|
21
|
+
.describe('Cap on returned findings. Defaults to 50.'),
|
|
22
|
+
};
|
|
23
|
+
export const findSimilarConfig = {
|
|
24
|
+
title: 'Find structurally similar findings',
|
|
25
|
+
description: 'Given one SastFinding id, return other findings in the same project that share the same rule_id ' +
|
|
26
|
+
'and/or taint sink type. Use after triaging a finding to catch the same vulnerability pattern ' +
|
|
27
|
+
'elsewhere without re-scanning or re-prompting.',
|
|
28
|
+
inputSchema: findSimilarInputShape,
|
|
29
|
+
};
|
|
30
|
+
export function makeFindSimilarHandler(ctx) {
|
|
31
|
+
return async (args) => {
|
|
32
|
+
const root = resolve(args.project_root);
|
|
33
|
+
const { analysis, cacheHit } = await ctx.cache.getOrCompute(root, {});
|
|
34
|
+
const matchBy = args.match_by ?? 'rule_and_sink';
|
|
35
|
+
const cap = Math.min(args.max_results ?? 50, MAX_FINDINGS);
|
|
36
|
+
// Locate anchor.
|
|
37
|
+
let anchor = null;
|
|
38
|
+
for (const fa of analysis.files) {
|
|
39
|
+
for (const f of fa.analysis.findings ?? []) {
|
|
40
|
+
if (f.id === args.finding_id) {
|
|
41
|
+
const sink = fa.analysis.taint?.flows?.find((fl) => fl.sink_line === f.line);
|
|
42
|
+
anchor = {
|
|
43
|
+
rule_id: f.rule_id,
|
|
44
|
+
sink_type: sink?.sink_type,
|
|
45
|
+
file: fa.file,
|
|
46
|
+
line: f.line,
|
|
47
|
+
};
|
|
48
|
+
break;
|
|
49
|
+
}
|
|
50
|
+
}
|
|
51
|
+
if (anchor)
|
|
52
|
+
break;
|
|
53
|
+
}
|
|
54
|
+
if (!anchor) {
|
|
55
|
+
return errorResult(`Finding not found: ${args.finding_id}. Call \`scan\` first, then pass an id from its output.`);
|
|
56
|
+
}
|
|
57
|
+
// Collect matches (exclude the anchor itself).
|
|
58
|
+
const matches = [];
|
|
59
|
+
for (const fa of analysis.files) {
|
|
60
|
+
for (const f of fa.analysis.findings ?? []) {
|
|
61
|
+
if (f.id === args.finding_id)
|
|
62
|
+
continue;
|
|
63
|
+
const sink = fa.analysis.taint?.flows?.find((fl) => fl.sink_line === f.line);
|
|
64
|
+
const sinkType = sink?.sink_type;
|
|
65
|
+
const ruleMatch = f.rule_id === anchor.rule_id;
|
|
66
|
+
const sinkMatch = sinkType && anchor.sink_type && sinkType === anchor.sink_type;
|
|
67
|
+
let isMatch = false;
|
|
68
|
+
if (matchBy === 'rule_and_sink')
|
|
69
|
+
isMatch = Boolean(ruleMatch && (anchor.sink_type ? sinkMatch : true));
|
|
70
|
+
else if (matchBy === 'rule')
|
|
71
|
+
isMatch = ruleMatch;
|
|
72
|
+
else if (matchBy === 'sink')
|
|
73
|
+
isMatch = Boolean(sinkMatch);
|
|
74
|
+
if (!isMatch)
|
|
75
|
+
continue;
|
|
76
|
+
matches.push({
|
|
77
|
+
id: f.id,
|
|
78
|
+
rule_id: f.rule_id,
|
|
79
|
+
category: f.category,
|
|
80
|
+
severity: f.severity,
|
|
81
|
+
file: fa.file,
|
|
82
|
+
line: f.line,
|
|
83
|
+
sink_type: sinkType,
|
|
84
|
+
message: truncateString(f.message, 512),
|
|
85
|
+
snippet: truncateString(f.snippet, 512),
|
|
86
|
+
});
|
|
87
|
+
}
|
|
88
|
+
}
|
|
89
|
+
const { items, truncated, totalCount } = truncateArray(matches, cap);
|
|
90
|
+
return textResult({
|
|
91
|
+
projectRoot: root,
|
|
92
|
+
cacheHit,
|
|
93
|
+
anchor: {
|
|
94
|
+
id: args.finding_id,
|
|
95
|
+
rule_id: anchor.rule_id,
|
|
96
|
+
sink_type: anchor.sink_type,
|
|
97
|
+
file: anchor.file,
|
|
98
|
+
line: anchor.line,
|
|
99
|
+
},
|
|
100
|
+
matchBy,
|
|
101
|
+
totalMatches: totalCount,
|
|
102
|
+
truncated,
|
|
103
|
+
similar: items,
|
|
104
|
+
});
|
|
105
|
+
};
|
|
106
|
+
}
|
|
107
|
+
//# sourceMappingURL=find-similar.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"find-similar.js","sourceRoot":"","sources":["../../src/tools/find-similar.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* `list_entry_points` tool — enumerate attacker-reachable entry points.
|
|
3
|
+
*/
|
|
4
|
+
import { z } from 'zod';
|
|
5
|
+
import type { ToolContext, ToolResult } from './types.js';
|
|
6
|
+
export declare const listEntryPointsInputShape: {
|
|
7
|
+
readonly project_root: z.ZodString;
|
|
8
|
+
readonly language: z.ZodOptional<z.ZodEnum<["java", "javascript", "typescript", "python", "go", "rust", "bash", "html"]>>;
|
|
9
|
+
};
|
|
10
|
+
export declare const listEntryPointsConfig: {
|
|
11
|
+
readonly title: "List attacker-reachable entry points";
|
|
12
|
+
readonly description: string;
|
|
13
|
+
readonly inputSchema: {
|
|
14
|
+
readonly project_root: z.ZodString;
|
|
15
|
+
readonly language: z.ZodOptional<z.ZodEnum<["java", "javascript", "typescript", "python", "go", "rust", "bash", "html"]>>;
|
|
16
|
+
};
|
|
17
|
+
};
|
|
18
|
+
export declare function makeListEntryPointsHandler(ctx: ToolContext): (args: {
|
|
19
|
+
project_root: string;
|
|
20
|
+
language?: "java" | "javascript" | "typescript" | "python" | "go" | "rust" | "bash" | "html";
|
|
21
|
+
}) => Promise<ToolResult>;
|
|
22
|
+
//# sourceMappingURL=list-entry-points.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"list-entry-points.d.ts","sourceRoot":"","sources":["../../src/tools/list-entry-points.ts"],"names":[],"mappings":"AAAA;;GAEG;AAEH,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAC;AAExB,OAAO,KAAK,EAAE,WAAW,EAAE,UAAU,EAAE,MAAM,YAAY,CAAC;AAI1D,eAAO,MAAM,yBAAyB;;;CAK5B,CAAC;AAEX,eAAO,MAAM,qBAAqB;;;;;;;CAQxB,CAAC;AAEX,wBAAgB,0BAA0B,CAAC,GAAG,EAAE,WAAW,IAC3C,MAAM;IAClB,YAAY,EAAE,MAAM,CAAC;IACrB,QAAQ,CAAC,EAAE,MAAM,GAAG,YAAY,GAAG,YAAY,GAAG,QAAQ,GAAG,IAAI,GAAG,MAAM,GAAG,MAAM,GAAG,MAAM,CAAC;CAC9F,KAAG,OAAO,CAAC,UAAU,CAAC,CA0CxB"}
|
|
@@ -0,0 +1,71 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* `list_entry_points` tool — enumerate attacker-reachable entry points.
|
|
3
|
+
*/
|
|
4
|
+
import { z } from 'zod';
|
|
5
|
+
import { resolve } from 'path';
|
|
6
|
+
import { textResult } from './types.js';
|
|
7
|
+
import { truncateArray, MAX_ENTRY_POINTS } from '../util/serialize.js';
|
|
8
|
+
export const listEntryPointsInputShape = {
|
|
9
|
+
project_root: z.string().describe('Absolute path to the project root.'),
|
|
10
|
+
language: z.enum(['java', 'javascript', 'typescript', 'python', 'go', 'rust', 'bash', 'html'])
|
|
11
|
+
.optional()
|
|
12
|
+
.describe('Restrict to a single language.'),
|
|
13
|
+
};
|
|
14
|
+
export const listEntryPointsConfig = {
|
|
15
|
+
title: 'List attacker-reachable entry points',
|
|
16
|
+
description: 'Enumerate all entry-point methods (HTTP route handlers, middlewares, event listeners, cron/queue ' +
|
|
17
|
+
'consumers) grouped by framework and language. Sourced from circle-ir `runtime_registrations` — the ' +
|
|
18
|
+
'call-graph edges that framework registration establishes but the raw AST does not surface. Answers ' +
|
|
19
|
+
'"what is the attack surface of this codebase?"',
|
|
20
|
+
inputSchema: listEntryPointsInputShape,
|
|
21
|
+
};
|
|
22
|
+
export function makeListEntryPointsHandler(ctx) {
|
|
23
|
+
return async (args) => {
|
|
24
|
+
const root = resolve(args.project_root);
|
|
25
|
+
const { analysis, cacheHit } = await ctx.cache.getOrCompute(root, {});
|
|
26
|
+
const entryPoints = [];
|
|
27
|
+
for (const fa of analysis.files) {
|
|
28
|
+
if (args.language && fa.analysis.meta.language !== args.language)
|
|
29
|
+
continue;
|
|
30
|
+
for (const reg of fa.analysis.runtime_registrations ?? []) {
|
|
31
|
+
entryPoints.push({
|
|
32
|
+
file: fa.file,
|
|
33
|
+
language: fa.analysis.meta.language,
|
|
34
|
+
kind: reg.kind,
|
|
35
|
+
framework: reg.framework,
|
|
36
|
+
method: reg.handler.name,
|
|
37
|
+
handlerLine: reg.handler.line,
|
|
38
|
+
registrar: {
|
|
39
|
+
method: reg.registrar.method,
|
|
40
|
+
receiver: reg.registrar.receiver,
|
|
41
|
+
line: reg.registrar.line,
|
|
42
|
+
},
|
|
43
|
+
route: reg.path,
|
|
44
|
+
});
|
|
45
|
+
}
|
|
46
|
+
}
|
|
47
|
+
const byFramework = countBy(entryPoints, e => String(e.framework ?? 'unknown'));
|
|
48
|
+
const byLanguage = countBy(entryPoints, e => String(e.language ?? 'unknown'));
|
|
49
|
+
const byKind = countBy(entryPoints, e => String(e.kind ?? 'unknown'));
|
|
50
|
+
const { items, truncated, totalCount } = truncateArray(entryPoints, MAX_ENTRY_POINTS);
|
|
51
|
+
return textResult({
|
|
52
|
+
projectRoot: root,
|
|
53
|
+
cacheHit,
|
|
54
|
+
totalEntryPoints: totalCount,
|
|
55
|
+
truncated,
|
|
56
|
+
byFramework,
|
|
57
|
+
byLanguage,
|
|
58
|
+
byKind,
|
|
59
|
+
entryPoints: items,
|
|
60
|
+
});
|
|
61
|
+
};
|
|
62
|
+
}
|
|
63
|
+
function countBy(items, key) {
|
|
64
|
+
const out = {};
|
|
65
|
+
for (const i of items) {
|
|
66
|
+
const k = key(i);
|
|
67
|
+
out[k] = (out[k] ?? 0) + 1;
|
|
68
|
+
}
|
|
69
|
+
return out;
|
|
70
|
+
}
|
|
71
|
+
//# sourceMappingURL=list-entry-points.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"list-entry-points.js","sourceRoot":"","sources":["../../src/tools/list-entry-points.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* `list_reachable_sinks` tool — enumerate every sink of a given category
|
|
3
|
+
* that has a demonstrated taint flow (per-file or cross-file). Filters
|
|
4
|
+
* out sinks that are lexically present but not reachable from any source.
|
|
5
|
+
*
|
|
6
|
+
* Answers "which SQL sinks in this project actually receive tainted
|
|
7
|
+
* data?" — the deterministic answer an LLM cannot produce alone.
|
|
8
|
+
*/
|
|
9
|
+
import { z } from 'zod';
|
|
10
|
+
import type { ToolContext, ToolResult } from './types.js';
|
|
11
|
+
export declare const listReachableSinksInputShape: {
|
|
12
|
+
readonly project_root: z.ZodString;
|
|
13
|
+
readonly sink_type: z.ZodOptional<z.ZodString>;
|
|
14
|
+
readonly language: z.ZodOptional<z.ZodEnum<["java", "javascript", "typescript", "python", "go", "rust", "bash", "html"]>>;
|
|
15
|
+
readonly min_confidence: z.ZodOptional<z.ZodNumber>;
|
|
16
|
+
};
|
|
17
|
+
export declare const listReachableSinksConfig: {
|
|
18
|
+
readonly title: "List reachable sinks (with taint flow)";
|
|
19
|
+
readonly description: string;
|
|
20
|
+
readonly inputSchema: {
|
|
21
|
+
readonly project_root: z.ZodString;
|
|
22
|
+
readonly sink_type: z.ZodOptional<z.ZodString>;
|
|
23
|
+
readonly language: z.ZodOptional<z.ZodEnum<["java", "javascript", "typescript", "python", "go", "rust", "bash", "html"]>>;
|
|
24
|
+
readonly min_confidence: z.ZodOptional<z.ZodNumber>;
|
|
25
|
+
};
|
|
26
|
+
};
|
|
27
|
+
export declare function makeListReachableSinksHandler(ctx: ToolContext): (args: {
|
|
28
|
+
project_root: string;
|
|
29
|
+
sink_type?: string;
|
|
30
|
+
language?: string;
|
|
31
|
+
min_confidence?: number;
|
|
32
|
+
}) => Promise<ToolResult>;
|
|
33
|
+
//# sourceMappingURL=list-reachable-sinks.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"list-reachable-sinks.d.ts","sourceRoot":"","sources":["../../src/tools/list-reachable-sinks.ts"],"names":[],"mappings":"AAAA;;;;;;;GAOG;AAEH,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAC;AAExB,OAAO,KAAK,EAAE,WAAW,EAAE,UAAU,EAAE,MAAM,YAAY,CAAC;AAI1D,eAAO,MAAM,4BAA4B;;;;;CAS/B,CAAC;AAEX,eAAO,MAAM,wBAAwB;;;;;;;;;CAQ3B,CAAC;AAiBX,wBAAgB,6BAA6B,CAAC,GAAG,EAAE,WAAW,IAC9C,MAAM;IAClB,YAAY,EAAE,MAAM,CAAC;IACrB,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,cAAc,CAAC,EAAE,MAAM,CAAC;CACzB,KAAG,OAAO,CAAC,UAAU,CAAC,CAkFxB"}
|
|
@@ -0,0 +1,116 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* `list_reachable_sinks` tool — enumerate every sink of a given category
|
|
3
|
+
* that has a demonstrated taint flow (per-file or cross-file). Filters
|
|
4
|
+
* out sinks that are lexically present but not reachable from any source.
|
|
5
|
+
*
|
|
6
|
+
* Answers "which SQL sinks in this project actually receive tainted
|
|
7
|
+
* data?" — the deterministic answer an LLM cannot produce alone.
|
|
8
|
+
*/
|
|
9
|
+
import { z } from 'zod';
|
|
10
|
+
import { resolve } from 'path';
|
|
11
|
+
import { textResult } from './types.js';
|
|
12
|
+
import { truncateArray, truncateString, MAX_FINDINGS } from '../util/serialize.js';
|
|
13
|
+
export const listReachableSinksInputShape = {
|
|
14
|
+
project_root: z.string().describe('Absolute path to the project root.'),
|
|
15
|
+
sink_type: z.string().optional()
|
|
16
|
+
.describe('Restrict to this sink category (e.g. "sql_injection", "command_injection", "xss").'),
|
|
17
|
+
language: z.enum(['java', 'javascript', 'typescript', 'python', 'go', 'rust', 'bash', 'html'])
|
|
18
|
+
.optional()
|
|
19
|
+
.describe('Restrict to one language.'),
|
|
20
|
+
min_confidence: z.number().min(0).max(1).optional()
|
|
21
|
+
.describe('Minimum flow confidence to include (0.0 - 1.0). Defaults to include all.'),
|
|
22
|
+
};
|
|
23
|
+
export const listReachableSinksConfig = {
|
|
24
|
+
title: 'List reachable sinks (with taint flow)',
|
|
25
|
+
description: 'List every sink of the requested category that has an actual taint flow reaching it (per-file OR ' +
|
|
26
|
+
'cross-file). Sinks with no reaching flow are excluded — this is the crucial difference vs. plain ' +
|
|
27
|
+
'"list all method calls named `Runtime.exec`". Use before proposing fixes so the LLM only inspects ' +
|
|
28
|
+
'sinks that are truly reachable from attacker-controlled input.',
|
|
29
|
+
inputSchema: listReachableSinksInputShape,
|
|
30
|
+
};
|
|
31
|
+
export function makeListReachableSinksHandler(ctx) {
|
|
32
|
+
return async (args) => {
|
|
33
|
+
const root = resolve(args.project_root);
|
|
34
|
+
const { analysis, cacheHit } = await ctx.cache.getOrCompute(root, {});
|
|
35
|
+
const minLevel = args.min_confidence ?? 0;
|
|
36
|
+
const passesConfidence = (c) => {
|
|
37
|
+
if (c === undefined)
|
|
38
|
+
return true;
|
|
39
|
+
return c >= minLevel;
|
|
40
|
+
};
|
|
41
|
+
const reachable = [];
|
|
42
|
+
// Per-file taint flows.
|
|
43
|
+
for (const fa of analysis.files) {
|
|
44
|
+
const lang = fa.analysis.meta.language;
|
|
45
|
+
if (args.language && lang !== args.language)
|
|
46
|
+
continue;
|
|
47
|
+
for (const flow of fa.analysis.taint?.flows ?? []) {
|
|
48
|
+
if (args.sink_type && flow.sink_type !== args.sink_type)
|
|
49
|
+
continue;
|
|
50
|
+
if (!passesConfidence(flow.confidence))
|
|
51
|
+
continue;
|
|
52
|
+
reachable.push({
|
|
53
|
+
file: fa.file,
|
|
54
|
+
language: lang,
|
|
55
|
+
sink_type: flow.sink_type,
|
|
56
|
+
sink_line: flow.sink_line,
|
|
57
|
+
source_type: flow.source_type,
|
|
58
|
+
source_line: flow.source_line,
|
|
59
|
+
confidence: flow.confidence,
|
|
60
|
+
sanitized: flow.sanitized,
|
|
61
|
+
scope: 'per-file',
|
|
62
|
+
});
|
|
63
|
+
}
|
|
64
|
+
}
|
|
65
|
+
// Cross-file taint paths (indexed on the analysis root).
|
|
66
|
+
for (const path of analysis.taint_paths) {
|
|
67
|
+
if (args.sink_type && path.sink.type !== args.sink_type)
|
|
68
|
+
continue;
|
|
69
|
+
// Language filter is best-effort: find the file's language via the sink file.
|
|
70
|
+
if (args.language) {
|
|
71
|
+
const fa = analysis.files.find((f) => f.file === path.sink.file);
|
|
72
|
+
if (!fa)
|
|
73
|
+
continue;
|
|
74
|
+
if (fa.analysis.meta.language !== args.language)
|
|
75
|
+
continue;
|
|
76
|
+
}
|
|
77
|
+
if (!passesConfidence(path.confidence))
|
|
78
|
+
continue;
|
|
79
|
+
reachable.push({
|
|
80
|
+
file: path.sink.file,
|
|
81
|
+
language: analysis.files.find((f) => f.file === path.sink.file)?.analysis.meta.language ?? 'unknown',
|
|
82
|
+
sink_type: path.sink.type,
|
|
83
|
+
sink_line: path.sink.line,
|
|
84
|
+
source_type: path.source.type,
|
|
85
|
+
source_line: path.source.line,
|
|
86
|
+
confidence: path.confidence,
|
|
87
|
+
scope: 'cross-file',
|
|
88
|
+
path_id: path.id,
|
|
89
|
+
path_hops: path.hops.length,
|
|
90
|
+
snippet: truncateString(path.sink.code, 512),
|
|
91
|
+
});
|
|
92
|
+
}
|
|
93
|
+
const byType = {};
|
|
94
|
+
const byLanguage = {};
|
|
95
|
+
for (const r of reachable) {
|
|
96
|
+
byType[r.sink_type] = (byType[r.sink_type] ?? 0) + 1;
|
|
97
|
+
byLanguage[r.language] = (byLanguage[r.language] ?? 0) + 1;
|
|
98
|
+
}
|
|
99
|
+
const { items, truncated, totalCount } = truncateArray(reachable, MAX_FINDINGS);
|
|
100
|
+
return textResult({
|
|
101
|
+
projectRoot: root,
|
|
102
|
+
cacheHit,
|
|
103
|
+
filters: {
|
|
104
|
+
sink_type: args.sink_type ?? 'any',
|
|
105
|
+
language: args.language ?? 'any',
|
|
106
|
+
min_confidence: args.min_confidence ?? 'any',
|
|
107
|
+
},
|
|
108
|
+
totalReachable: totalCount,
|
|
109
|
+
truncated,
|
|
110
|
+
bySinkType: byType,
|
|
111
|
+
byLanguage,
|
|
112
|
+
sinks: items,
|
|
113
|
+
});
|
|
114
|
+
};
|
|
115
|
+
}
|
|
116
|
+
//# sourceMappingURL=list-reachable-sinks.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"list-reachable-sinks.js","sourceRoot":"","sources":["../../src/tools/list-reachable-sinks.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* `refresh` tool — manual cache invalidation. The server auto-invalidates
|
|
3
|
+
* on file mtime change, but callers may want to force a re-scan (e.g.
|
|
4
|
+
* after a git checkout or when developing analyzer rules).
|
|
5
|
+
*/
|
|
6
|
+
import { z } from 'zod';
|
|
7
|
+
import type { ToolContext, ToolResult } from './types.js';
|
|
8
|
+
export declare const refreshInputShape: {
|
|
9
|
+
readonly project_root: z.ZodOptional<z.ZodString>;
|
|
10
|
+
};
|
|
11
|
+
export declare const refreshConfig: {
|
|
12
|
+
readonly title: "Refresh analysis cache";
|
|
13
|
+
readonly description: string;
|
|
14
|
+
readonly inputSchema: {
|
|
15
|
+
readonly project_root: z.ZodOptional<z.ZodString>;
|
|
16
|
+
};
|
|
17
|
+
};
|
|
18
|
+
export declare function makeRefreshHandler(ctx: ToolContext): (args: {
|
|
19
|
+
project_root?: string;
|
|
20
|
+
}) => Promise<ToolResult>;
|
|
21
|
+
//# sourceMappingURL=refresh.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"refresh.d.ts","sourceRoot":"","sources":["../../src/tools/refresh.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAEH,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAC;AAExB,OAAO,KAAK,EAAE,WAAW,EAAE,UAAU,EAAE,MAAM,YAAY,CAAC;AAG1D,eAAO,MAAM,iBAAiB;;CAGpB,CAAC;AAEX,eAAO,MAAM,aAAa;;;;;;CAOhB,CAAC;AAEX,wBAAgB,kBAAkB,CAAC,GAAG,EAAE,WAAW,IACnC,MAAM;IAAE,YAAY,CAAC,EAAE,MAAM,CAAA;CAAE,KAAG,OAAO,CAAC,UAAU,CAAC,CAiBpE"}
|