@skaleagents/swarm 0.5.0 → 0.6.1
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 +88 -4
- package/dist/application/graph.d.ts +45 -0
- package/dist/application/graph.js +264 -0
- package/dist/application/intake.d.ts +63 -0
- package/dist/application/intake.js +182 -0
- package/dist/application/review.d.ts +71 -0
- package/dist/application/review.js +360 -0
- package/dist/application/tools.d.ts +2 -0
- package/dist/application/tools.js +94 -0
- package/dist/iac/scan.js +2 -1
- package/dist/review.d.ts +1 -1
- package/dist/review.js +1 -2
- package/dist/server.js +11 -12
- package/dist/version.d.ts +1 -0
- package/dist/version.js +1 -0
- package/package.json +5 -4
|
@@ -0,0 +1,94 @@
|
|
|
1
|
+
import { z } from "zod";
|
|
2
|
+
import { requireApiAuth, unauthorizedContent } from "../auth.js";
|
|
3
|
+
import { ScanInputError } from "../iac/parse.js";
|
|
4
|
+
import { contextSchema, fileSchema, planReview, consultationInstructions, } from "./intake.js";
|
|
5
|
+
import { reviewApplication } from "./review.js";
|
|
6
|
+
async function run(remote, compute) {
|
|
7
|
+
if (!remote) {
|
|
8
|
+
const auth = await requireApiAuth();
|
|
9
|
+
if (!auth.ok)
|
|
10
|
+
return unauthorizedContent(auth);
|
|
11
|
+
}
|
|
12
|
+
try {
|
|
13
|
+
const output = compute();
|
|
14
|
+
return {
|
|
15
|
+
content: [
|
|
16
|
+
{ type: "text", text: JSON.stringify(output, null, 2) },
|
|
17
|
+
],
|
|
18
|
+
structuredContent: output,
|
|
19
|
+
};
|
|
20
|
+
}
|
|
21
|
+
catch (error) {
|
|
22
|
+
if (!(error instanceof ScanInputError))
|
|
23
|
+
throw error;
|
|
24
|
+
return {
|
|
25
|
+
isError: true,
|
|
26
|
+
content: [
|
|
27
|
+
{
|
|
28
|
+
type: "text",
|
|
29
|
+
text: JSON.stringify({
|
|
30
|
+
error: "invalid_input",
|
|
31
|
+
message: error.message,
|
|
32
|
+
}),
|
|
33
|
+
},
|
|
34
|
+
],
|
|
35
|
+
};
|
|
36
|
+
}
|
|
37
|
+
}
|
|
38
|
+
export function registerConsultation(server, remote) {
|
|
39
|
+
const annotations = {
|
|
40
|
+
readOnlyHint: true,
|
|
41
|
+
destructiveHint: false,
|
|
42
|
+
openWorldHint: false,
|
|
43
|
+
};
|
|
44
|
+
const security = { securitySchemes: [{ type: "oauth2", scopes: ["mcp"] }] };
|
|
45
|
+
server.registerTool("plan_architecture_review", {
|
|
46
|
+
title: "Plan a whole-application architecture review",
|
|
47
|
+
description: "Start an interactive architecture consultation. Supply repository-relative file paths and known project context. Returns prioritized files to read, review areas, and up to three follow-up questions. Covers the whole application, including Next.js apps, not only infrastructure or scaling.",
|
|
48
|
+
annotations,
|
|
49
|
+
_meta: security,
|
|
50
|
+
inputSchema: {
|
|
51
|
+
filePaths: z
|
|
52
|
+
.array(z.string().min(1).max(300))
|
|
53
|
+
.max(3000)
|
|
54
|
+
.describe("Repository file inventory, relative to the application package root; use the client's workspace tools to list files"),
|
|
55
|
+
context: contextSchema,
|
|
56
|
+
},
|
|
57
|
+
}, ({ filePaths, context }) => run(remote, () => planReview(filePaths, context)));
|
|
58
|
+
server.registerTool("review_application_architecture", {
|
|
59
|
+
title: "Review whole-application architecture",
|
|
60
|
+
description: "Review related source files as an application. Builds a JS/TS import graph, checks Next.js server/client and runtime boundaries, maps routes and mutations, and returns evidence-backed findings plus questions covering data, auth, reliability, tests, deployment and product fit. Pass answers in context on subsequent calls. No repository fetch or execution; the connected assistant reasons about system-level tradeoffs using the returned evidence.",
|
|
61
|
+
annotations,
|
|
62
|
+
_meta: security,
|
|
63
|
+
inputSchema: {
|
|
64
|
+
files: z
|
|
65
|
+
.array(fileSchema)
|
|
66
|
+
.min(1)
|
|
67
|
+
.max(80)
|
|
68
|
+
.describe("Related source/config/test files with repository-relative paths; include package.json and tsconfig.json. At most 500,000 combined content characters"),
|
|
69
|
+
context: contextSchema,
|
|
70
|
+
},
|
|
71
|
+
}, ({ files, context }) => run(remote, () => reviewApplication(files, context)));
|
|
72
|
+
server.registerPrompt("architecture_consultation", {
|
|
73
|
+
title: "Independent application architecture consultation",
|
|
74
|
+
description: "Guide a multi-turn whole-application review with source evidence, follow-up questions, and design tradeoffs.",
|
|
75
|
+
argsSchema: {
|
|
76
|
+
goal: z
|
|
77
|
+
.string()
|
|
78
|
+
.max(3000)
|
|
79
|
+
.optional()
|
|
80
|
+
.describe("The architecture question or business goal to assess"),
|
|
81
|
+
},
|
|
82
|
+
}, ({ goal }) => ({
|
|
83
|
+
description: "Evidence-led architecture consultation",
|
|
84
|
+
messages: [
|
|
85
|
+
{
|
|
86
|
+
role: "user",
|
|
87
|
+
content: {
|
|
88
|
+
type: "text",
|
|
89
|
+
text: `${consultationInstructions}\n\nReview goal: ${goal || "Assess the whole application's architecture and explain the highest-priority improvements."}`,
|
|
90
|
+
},
|
|
91
|
+
},
|
|
92
|
+
],
|
|
93
|
+
}));
|
|
94
|
+
}
|
package/dist/iac/scan.js
CHANGED
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import { parseIac } from "./parse.js";
|
|
2
2
|
import { resourceFindings } from "./rules.js";
|
|
3
|
+
import { VERSION } from "../version.js";
|
|
3
4
|
export const severityRank = {
|
|
4
5
|
info: 0,
|
|
5
6
|
low: 1,
|
|
@@ -30,7 +31,7 @@ export function scanIac(content, options = {}) {
|
|
|
30
31
|
const limit = options.maxFindings ?? 100;
|
|
31
32
|
return {
|
|
32
33
|
status: "completed",
|
|
33
|
-
engineVersion:
|
|
34
|
+
engineVersion: VERSION,
|
|
34
35
|
format: parsed.format,
|
|
35
36
|
focus: options.focus ?? "general",
|
|
36
37
|
summary: `Scanned ${parsed.resources.length} resources; ${findings.length} findings match the selected filters.`,
|
package/dist/review.d.ts
CHANGED
|
@@ -16,4 +16,4 @@ export type Finding = {
|
|
|
16
16
|
export declare function architectureFindings(content: string, focus: string): Finding[];
|
|
17
17
|
export declare function literalCredential(value: string): boolean;
|
|
18
18
|
export declare function externalHttp(value: string): boolean;
|
|
19
|
-
export declare function fetchPublicBotHints(
|
|
19
|
+
export declare function fetchPublicBotHints(): Promise<string[]>;
|
package/dist/review.js
CHANGED
|
@@ -168,13 +168,12 @@ export function externalHttp(value) {
|
|
|
168
168
|
return false;
|
|
169
169
|
}
|
|
170
170
|
}
|
|
171
|
-
export async function fetchPublicBotHints(
|
|
171
|
+
export async function fetchPublicBotHints() {
|
|
172
172
|
try {
|
|
173
173
|
const res = await fetch(`${getApiUrl()}/api/bots`, {
|
|
174
174
|
signal: AbortSignal.timeout(10_000),
|
|
175
175
|
headers: {
|
|
176
176
|
Accept: "application/json",
|
|
177
|
-
...(token ? { Authorization: `Bearer ${token}` } : {}),
|
|
178
177
|
},
|
|
179
178
|
});
|
|
180
179
|
if (!res.ok)
|
package/dist/server.js
CHANGED
|
@@ -1,9 +1,11 @@
|
|
|
1
1
|
import { McpServer } from "@modelcontextprotocol/sdk/server/mcp.js";
|
|
2
2
|
import { z } from "zod";
|
|
3
|
-
import {
|
|
3
|
+
import { requireApiAuth, unauthorizedContent } from "./auth.js";
|
|
4
4
|
import { architectureFindings, fetchPublicBotHints } from "./review.js";
|
|
5
5
|
import { looksLikeIac, ScanInputError } from "./iac/parse.js";
|
|
6
6
|
import { filterFindings, scanIac, summarize } from "./iac/scan.js";
|
|
7
|
+
import { registerConsultation } from "./application/tools.js";
|
|
8
|
+
import { VERSION } from "./version.js";
|
|
7
9
|
const contentSchema = z
|
|
8
10
|
.string()
|
|
9
11
|
.min(1)
|
|
@@ -48,13 +50,13 @@ function inputError(error) {
|
|
|
48
50
|
};
|
|
49
51
|
}
|
|
50
52
|
export function createServer(remote = false) {
|
|
51
|
-
const server = new McpServer({
|
|
52
|
-
|
|
53
|
-
version: "0.5.0",
|
|
53
|
+
const server = new McpServer({ name: "skaleagents-swarm", version: VERSION }, {
|
|
54
|
+
instructions: "For a whole application architecture consultation, start with plan_architecture_review, read relevant files with the client's workspace tools, then call review_application_architecture. Ask its follow-up questions and carry answers forward in context. Use review_architecture for individual source snippets and scan_iac for infrastructure. Ground conclusions in the returned evidence and coverage limits.",
|
|
54
55
|
});
|
|
56
|
+
registerConsultation(server, remote);
|
|
55
57
|
server.registerTool("review_architecture", {
|
|
56
58
|
title: "Review architecture",
|
|
57
|
-
description: "Review
|
|
59
|
+
description: "Review individual source snippets or parsed infrastructure for security, reliability, and cost risks. For a whole application or Next.js architecture consultation, use plan_architecture_review and review_application_architecture instead.",
|
|
58
60
|
annotations: {
|
|
59
61
|
readOnlyHint: true,
|
|
60
62
|
destructiveHint: false,
|
|
@@ -77,14 +79,11 @@ export function createServer(remote = false) {
|
|
|
77
79
|
.describe("Content format: terraform, cloudformation, kubernetes, application, auto"),
|
|
78
80
|
},
|
|
79
81
|
}, async ({ content, focus, format, minSeverity, maxFindings }) => {
|
|
80
|
-
|
|
82
|
+
const botHints = fetchPublicBotHints();
|
|
81
83
|
if (!remote) {
|
|
82
84
|
const auth = await requireApiAuth();
|
|
83
85
|
if (!auth.ok)
|
|
84
86
|
return unauthorizedContent(auth);
|
|
85
|
-
token = (await getApiAccessToken()) ?? undefined;
|
|
86
|
-
if (!token)
|
|
87
|
-
return unauthorizedContent({ ok: false, reason: "oauth_failed" });
|
|
88
87
|
}
|
|
89
88
|
try {
|
|
90
89
|
const options = { focus, minSeverity, maxFindings };
|
|
@@ -92,13 +91,13 @@ export function createServer(remote = false) {
|
|
|
92
91
|
(format !== "auto" || looksLikeIac(content))) {
|
|
93
92
|
return result({
|
|
94
93
|
...scanIac(content, { ...options, format }),
|
|
95
|
-
botHints: await
|
|
94
|
+
botHints: await botHints,
|
|
96
95
|
});
|
|
97
96
|
}
|
|
98
97
|
const findings = filterFindings(architectureFindings(content, focus).slice(1), options);
|
|
99
98
|
return result({
|
|
100
99
|
status: "completed",
|
|
101
|
-
engineVersion:
|
|
100
|
+
engineVersion: VERSION,
|
|
102
101
|
format: "application",
|
|
103
102
|
focus,
|
|
104
103
|
summary: `Application review completed; ${findings.length} findings match the selected filters.`,
|
|
@@ -109,7 +108,7 @@ export function createServer(remote = false) {
|
|
|
109
108
|
limitations: [
|
|
110
109
|
"Application checks are text patterns, not a language-aware or runtime analysis. Findings do not establish that code is safe.",
|
|
111
110
|
],
|
|
112
|
-
botHints: await
|
|
111
|
+
botHints: await botHints,
|
|
113
112
|
});
|
|
114
113
|
}
|
|
115
114
|
catch (error) {
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export declare const VERSION = "0.6.1";
|
package/dist/version.js
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export const VERSION = "0.6.1";
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@skaleagents/swarm",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.6.1",
|
|
4
4
|
"private": false,
|
|
5
5
|
"publishConfig": {
|
|
6
6
|
"access": "public"
|
|
@@ -24,7 +24,8 @@
|
|
|
24
24
|
"start": "node dist/index.js",
|
|
25
25
|
"dev": "tsx src/index.ts",
|
|
26
26
|
"typecheck": "tsc --noEmit",
|
|
27
|
-
"test": "tsx --test src/*.test.ts src/iac/*.test.ts",
|
|
27
|
+
"test": "tsx --test src/*.test.ts src/iac/*.test.ts src/application/*.test.ts && npm run build && node --test scripts/*.test.mjs",
|
|
28
|
+
"benchmark:tool": "npm run build && node scripts/benchmark-tool-latency.mjs",
|
|
28
29
|
"smoke": "tsx scripts/smoke-tools.mjs"
|
|
29
30
|
},
|
|
30
31
|
"engines": {
|
|
@@ -33,12 +34,12 @@
|
|
|
33
34
|
"dependencies": {
|
|
34
35
|
"@modelcontextprotocol/sdk": "^1.30.0",
|
|
35
36
|
"hcl2-parser": "^1.0.3",
|
|
37
|
+
"typescript": "^5.9.3",
|
|
36
38
|
"yaml": "^2.9.1",
|
|
37
39
|
"zod": "^4.4.3"
|
|
38
40
|
},
|
|
39
41
|
"devDependencies": {
|
|
40
42
|
"@types/node": "^22.20.1",
|
|
41
|
-
"tsx": "^4.23.12"
|
|
42
|
-
"typescript": "^5.7.3"
|
|
43
|
+
"tsx": "^4.23.12"
|
|
43
44
|
}
|
|
44
45
|
}
|