shellward 0.5.14 → 0.5.16
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 +20 -0
- package/dist/index.js +1 -1
- package/dist/mcp-server.js +23 -40
- package/package.json +2 -2
- package/server.json +2 -2
- package/src/index.ts +1 -1
- package/src/mcp-server.ts +21 -42
package/README.md
CHANGED
|
@@ -61,6 +61,7 @@ Your AI agent has full access to tools — shell, email, HTTP, file system. One
|
|
|
61
61
|
| **LangChain** | SDK | LLM application framework |
|
|
62
62
|
| **AutoGPT** | SDK | Autonomous AI agents |
|
|
63
63
|
| **OpenAI Agents** | SDK | GPT agent platform |
|
|
64
|
+
| **Hermes Agent** | MCP Server | Nous Research's self-improving agent — register via MCP Integration |
|
|
64
65
|
| **Dify / Coze** | SDK | Low-code AI platforms |
|
|
65
66
|
| **Any MCP Client** | MCP Server | stdio JSON-RPC, zero dependencies |
|
|
66
67
|
| **Any AI Agent** | SDK | `npm install shellward` — 3 lines to integrate |
|
|
@@ -330,6 +331,7 @@ ShellWard is built for teams that need runtime security for AI agents — whethe
|
|
|
330
331
|
| **LangChain** | SDK | LLM 应用开发框架 |
|
|
331
332
|
| **AutoGPT** | SDK | 自主 AI Agent |
|
|
332
333
|
| **OpenAI Agents** | SDK | GPT Agent 平台 |
|
|
334
|
+
| **Hermes Agent** | MCP 服务器 | Nous Research 自改进 Agent — 通过 MCP Integration 接入 |
|
|
333
335
|
| **Dify / Coze** | SDK | 低代码 AI 平台 |
|
|
334
336
|
| **任意 MCP 客户端** | MCP 服务器 | stdio JSON-RPC,零依赖 |
|
|
335
337
|
| **任意 AI Agent** | SDK | `npm install shellward`,3 行代码接入 |
|
|
@@ -400,6 +402,24 @@ guard.checkOutbound('send_email', {...}) // → { allowed: false } (读过敏
|
|
|
400
402
|
>
|
|
401
403
|
> 最新研究 ([arXiv:2603.08665](https://arxiv.org/abs/2603.08665)) 显示 GenAI 在 7 小时内发现 38 个真实漏洞 — AI 驱动的攻击正在规模化,防御必须内建到 Agent 层。
|
|
402
404
|
|
|
405
|
+
### 交流 · Community
|
|
406
|
+
|
|
407
|
+
微信公众号 **「AI不止语」**(微信搜索 `AI_BuZhiYu`)— 技术问答 · 项目更新 · 实战文章
|
|
408
|
+
|
|
409
|
+
| 渠道 | 加入方式 |
|
|
410
|
+
|------|---------|
|
|
411
|
+
| QQ 群 | [点击加入](https://qm.qq.com/q/EeNQA9xCxy)(群号 1071280067) |
|
|
412
|
+
| 微信群 | 关注公众号后回复「群」获取入群方式 |
|
|
413
|
+
|
|
414
|
+
### 姊妹项目
|
|
415
|
+
|
|
416
|
+
| 项目 | 说明 |
|
|
417
|
+
|------|------|
|
|
418
|
+
| [ai-coding-guide](https://github.com/jnMetaCode/ai-coding-guide) | AI 编程工具实战指南 — 66 个 Claude Code 技巧 + 9 款工具最佳实践 + 可复制配置模板 |
|
|
419
|
+
| [agency-agents-zh](https://github.com/jnMetaCode/agency-agents-zh) | 187 个专业角色,让 AI 变成安全工程师、DBA、产品经理等 |
|
|
420
|
+
| [agency-orchestrator](https://github.com/jnMetaCode/agency-orchestrator) | 多智能体编排引擎 — 用 YAML 编排 187 个角色协作,支持 DeepSeek/Claude/OpenAI/Ollama,零代码 |
|
|
421
|
+
| [superpowers-zh](https://github.com/jnMetaCode/superpowers-zh) | AI 编程超能力 · 中文版 — 20 个 skills,让你的 AI 编程助手真正会干活 |
|
|
422
|
+
|
|
403
423
|
### 作者
|
|
404
424
|
|
|
405
425
|
[jnMetaCode](https://github.com/jnMetaCode) · Apache-2.0
|
package/dist/index.js
CHANGED
|
@@ -18,7 +18,7 @@ import { setupSessionGuard } from './layers/session-guard.js';
|
|
|
18
18
|
import { registerAllCommands } from './commands/index.js';
|
|
19
19
|
import { checkForUpdate } from './update-check.js';
|
|
20
20
|
import { runAutoCheckOnStartup } from './auto-check.js';
|
|
21
|
-
const CURRENT_VERSION = '0.5.
|
|
21
|
+
const CURRENT_VERSION = '0.5.16';
|
|
22
22
|
// Re-export core engine for SDK usage
|
|
23
23
|
export { ShellWard } from './core/engine.js';
|
|
24
24
|
/**
|
package/dist/mcp-server.js
CHANGED
|
@@ -18,6 +18,7 @@
|
|
|
18
18
|
// }
|
|
19
19
|
import { ShellWard } from './core/engine.js';
|
|
20
20
|
import { readFileSync } from 'fs';
|
|
21
|
+
import { createInterface } from 'readline';
|
|
21
22
|
import { fileURLToPath } from 'url';
|
|
22
23
|
import { dirname, join } from 'path';
|
|
23
24
|
const __dirname = dirname(fileURLToPath(import.meta.url));
|
|
@@ -290,51 +291,33 @@ function handleRequest(req) {
|
|
|
290
291
|
}
|
|
291
292
|
}
|
|
292
293
|
// ===== Stdio Transport =====
|
|
293
|
-
//
|
|
294
|
-
//
|
|
295
|
-
|
|
296
|
-
|
|
297
|
-
|
|
298
|
-
|
|
299
|
-
|
|
300
|
-
|
|
301
|
-
|
|
302
|
-
|
|
303
|
-
|
|
304
|
-
|
|
305
|
-
|
|
306
|
-
if (!lengthMatch) {
|
|
307
|
-
rawBuffer = rawBuffer.slice(headerEnd + 4);
|
|
308
|
-
continue;
|
|
309
|
-
}
|
|
310
|
-
const contentLength = parseInt(lengthMatch[1], 10);
|
|
311
|
-
const bodyStart = headerEnd + 4;
|
|
312
|
-
if (rawBuffer.length < bodyStart + contentLength)
|
|
313
|
-
break;
|
|
314
|
-
const body = rawBuffer.slice(bodyStart, bodyStart + contentLength).toString('utf8');
|
|
315
|
-
rawBuffer = rawBuffer.slice(bodyStart + contentLength);
|
|
316
|
-
try {
|
|
317
|
-
const req = JSON.parse(body);
|
|
318
|
-
const res = handleRequest(req);
|
|
319
|
-
if (res) {
|
|
320
|
-
send(res);
|
|
321
|
-
}
|
|
322
|
-
}
|
|
323
|
-
catch {
|
|
324
|
-
send({
|
|
325
|
-
jsonrpc: '2.0',
|
|
326
|
-
id: null,
|
|
327
|
-
error: { code: -32700, message: 'Parse error' },
|
|
328
|
-
});
|
|
294
|
+
// MCP stdio: newline-delimited JSON-RPC messages (no Content-Length framing).
|
|
295
|
+
// Each message is a single JSON object followed by \n.
|
|
296
|
+
// Messages MUST NOT contain embedded newlines.
|
|
297
|
+
const rl = createInterface({ input: process.stdin, terminal: false });
|
|
298
|
+
rl.on('line', (line) => {
|
|
299
|
+
const trimmed = line.trim();
|
|
300
|
+
if (!trimmed)
|
|
301
|
+
return;
|
|
302
|
+
try {
|
|
303
|
+
const req = JSON.parse(trimmed);
|
|
304
|
+
const res = handleRequest(req);
|
|
305
|
+
if (res) {
|
|
306
|
+
send(res);
|
|
329
307
|
}
|
|
330
308
|
}
|
|
309
|
+
catch {
|
|
310
|
+
send({
|
|
311
|
+
jsonrpc: '2.0',
|
|
312
|
+
id: null,
|
|
313
|
+
error: { code: -32700, message: 'Parse error' },
|
|
314
|
+
});
|
|
315
|
+
}
|
|
331
316
|
});
|
|
332
317
|
function send(msg) {
|
|
333
|
-
|
|
334
|
-
const header = `Content-Length: ${Buffer.byteLength(body)}\r\n\r\n`;
|
|
335
|
-
process.stdout.write(header + body);
|
|
318
|
+
process.stdout.write(JSON.stringify(msg) + '\n');
|
|
336
319
|
}
|
|
337
|
-
|
|
320
|
+
rl.on('close', () => process.exit(0));
|
|
338
321
|
process.stdin.on('error', () => process.exit(1));
|
|
339
322
|
// Log to stderr so it doesn't interfere with stdio protocol
|
|
340
323
|
process.stderr.write(`[ShellWard MCP] Server started (mode: ${guard.config.mode}, locale: ${guard.locale})\n`);
|
package/package.json
CHANGED
|
@@ -1,8 +1,8 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "shellward",
|
|
3
|
-
"version": "0.5.
|
|
3
|
+
"version": "0.5.16",
|
|
4
4
|
"mcpName": "io.github.jnMetaCode/shellward",
|
|
5
|
-
"description": "AI agent security & MCP security middleware — prompt injection detection, AI firewall, runtime guardrails & data-loss prevention for LLM tool calls. 8-layer defense against data exfiltration & dangerous commands. Zero dependencies. SDK + OpenClaw plugin. Supports LangChain, AutoGPT, Claude Code, Cursor, OpenAI Agents.",
|
|
5
|
+
"description": "AI agent security & MCP security middleware — prompt injection detection, AI firewall, runtime guardrails & data-loss prevention for LLM tool calls. 8-layer defense against data exfiltration & dangerous commands. Zero dependencies. SDK + OpenClaw plugin. Supports LangChain, AutoGPT, Claude Code, Cursor, OpenAI Agents, Hermes Agent.",
|
|
6
6
|
"keywords": [
|
|
7
7
|
"shellward",
|
|
8
8
|
"ai-security",
|
package/server.json
CHANGED
|
@@ -6,12 +6,12 @@
|
|
|
6
6
|
"url": "https://github.com/jnMetaCode/shellward",
|
|
7
7
|
"source": "github"
|
|
8
8
|
},
|
|
9
|
-
"version": "0.5.
|
|
9
|
+
"version": "0.5.15",
|
|
10
10
|
"packages": [
|
|
11
11
|
{
|
|
12
12
|
"registryType": "npm",
|
|
13
13
|
"identifier": "shellward",
|
|
14
|
-
"version": "0.5.
|
|
14
|
+
"version": "0.5.15",
|
|
15
15
|
"runtime": "node",
|
|
16
16
|
"transport": {
|
|
17
17
|
"type": "stdio"
|
package/src/index.ts
CHANGED
|
@@ -20,7 +20,7 @@ import { registerAllCommands } from './commands/index.js'
|
|
|
20
20
|
import { checkForUpdate } from './update-check.js'
|
|
21
21
|
import { runAutoCheckOnStartup } from './auto-check.js'
|
|
22
22
|
|
|
23
|
-
const CURRENT_VERSION = '0.5.
|
|
23
|
+
const CURRENT_VERSION = '0.5.16'
|
|
24
24
|
|
|
25
25
|
// Re-export core engine for SDK usage
|
|
26
26
|
export { ShellWard } from './core/engine.js'
|
package/src/mcp-server.ts
CHANGED
|
@@ -19,6 +19,7 @@
|
|
|
19
19
|
|
|
20
20
|
import { ShellWard } from './core/engine.js'
|
|
21
21
|
import { readFileSync } from 'fs'
|
|
22
|
+
import { createInterface } from 'readline'
|
|
22
23
|
import { fileURLToPath } from 'url'
|
|
23
24
|
import { dirname, join } from 'path'
|
|
24
25
|
|
|
@@ -332,58 +333,36 @@ function handleRequest(req: JsonRpcRequest): JsonRpcResponse | null {
|
|
|
332
333
|
}
|
|
333
334
|
|
|
334
335
|
// ===== Stdio Transport =====
|
|
335
|
-
//
|
|
336
|
-
//
|
|
336
|
+
// MCP stdio: newline-delimited JSON-RPC messages (no Content-Length framing).
|
|
337
|
+
// Each message is a single JSON object followed by \n.
|
|
338
|
+
// Messages MUST NOT contain embedded newlines.
|
|
337
339
|
|
|
338
|
-
|
|
340
|
+
const rl = createInterface({ input: process.stdin, terminal: false })
|
|
339
341
|
|
|
340
|
-
|
|
341
|
-
|
|
342
|
+
rl.on('line', (line: string) => {
|
|
343
|
+
const trimmed = line.trim()
|
|
344
|
+
if (!trimmed) return
|
|
342
345
|
|
|
343
|
-
|
|
344
|
-
|
|
345
|
-
|
|
346
|
-
|
|
347
|
-
|
|
348
|
-
if (headerEnd === -1) break
|
|
349
|
-
|
|
350
|
-
const header = rawBuffer.slice(0, headerEnd).toString('ascii')
|
|
351
|
-
const lengthMatch = header.match(/Content-Length:\s*(\d+)/i)
|
|
352
|
-
if (!lengthMatch) {
|
|
353
|
-
rawBuffer = rawBuffer.slice(headerEnd + 4)
|
|
354
|
-
continue
|
|
355
|
-
}
|
|
356
|
-
|
|
357
|
-
const contentLength = parseInt(lengthMatch[1], 10)
|
|
358
|
-
const bodyStart = headerEnd + 4
|
|
359
|
-
if (rawBuffer.length < bodyStart + contentLength) break
|
|
360
|
-
|
|
361
|
-
const body = rawBuffer.slice(bodyStart, bodyStart + contentLength).toString('utf8')
|
|
362
|
-
rawBuffer = rawBuffer.slice(bodyStart + contentLength)
|
|
363
|
-
|
|
364
|
-
try {
|
|
365
|
-
const req = JSON.parse(body) as JsonRpcRequest
|
|
366
|
-
const res = handleRequest(req)
|
|
367
|
-
if (res) {
|
|
368
|
-
send(res)
|
|
369
|
-
}
|
|
370
|
-
} catch {
|
|
371
|
-
send({
|
|
372
|
-
jsonrpc: '2.0',
|
|
373
|
-
id: null,
|
|
374
|
-
error: { code: -32700, message: 'Parse error' },
|
|
375
|
-
})
|
|
346
|
+
try {
|
|
347
|
+
const req = JSON.parse(trimmed) as JsonRpcRequest
|
|
348
|
+
const res = handleRequest(req)
|
|
349
|
+
if (res) {
|
|
350
|
+
send(res)
|
|
376
351
|
}
|
|
352
|
+
} catch {
|
|
353
|
+
send({
|
|
354
|
+
jsonrpc: '2.0',
|
|
355
|
+
id: null,
|
|
356
|
+
error: { code: -32700, message: 'Parse error' },
|
|
357
|
+
})
|
|
377
358
|
}
|
|
378
359
|
})
|
|
379
360
|
|
|
380
361
|
function send(msg: JsonRpcResponse) {
|
|
381
|
-
|
|
382
|
-
const header = `Content-Length: ${Buffer.byteLength(body)}\r\n\r\n`
|
|
383
|
-
process.stdout.write(header + body)
|
|
362
|
+
process.stdout.write(JSON.stringify(msg) + '\n')
|
|
384
363
|
}
|
|
385
364
|
|
|
386
|
-
|
|
365
|
+
rl.on('close', () => process.exit(0))
|
|
387
366
|
process.stdin.on('error', () => process.exit(1))
|
|
388
367
|
|
|
389
368
|
// Log to stderr so it doesn't interfere with stdio protocol
|