agentsafe 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.
Files changed (51) hide show
  1. package/.gitattributes +5 -0
  2. package/.github/workflows/ci.yml +34 -0
  3. package/CHANGELOG.md +13 -0
  4. package/CONTRIBUTING.md +23 -0
  5. package/LICENSE +21 -0
  6. package/README.md +128 -0
  7. package/SECURITY.md +22 -0
  8. package/dist/cli.d.ts +7 -0
  9. package/dist/cli.js +77 -0
  10. package/dist/cli.js.map +1 -0
  11. package/dist/index.d.ts +2 -0
  12. package/dist/index.js +4 -0
  13. package/dist/index.js.map +1 -0
  14. package/dist/rules/report.d.ts +4 -0
  15. package/dist/rules/report.js +71 -0
  16. package/dist/rules/report.js.map +1 -0
  17. package/dist/rules/scan.d.ts +2 -0
  18. package/dist/rules/scan.js +459 -0
  19. package/dist/rules/scan.js.map +1 -0
  20. package/dist/rules/types.d.ts +27 -0
  21. package/dist/rules/types.js +2 -0
  22. package/dist/rules/types.js.map +1 -0
  23. package/examples/safe-rules/.cursor/rules/typescript.mdc +15 -0
  24. package/examples/safe-rules/.cursorrules +1 -0
  25. package/examples/safe-rules/AGENTS.md +3 -0
  26. package/examples/safe-rules/CLAUDE.md +3 -0
  27. package/examples/safe-rules/GEMINI.md +3 -0
  28. package/examples/unsafe-rules/.cursor/rules/always-1.mdc +6 -0
  29. package/examples/unsafe-rules/.cursor/rules/always-2.mdc +6 -0
  30. package/examples/unsafe-rules/.cursor/rules/always-3.mdc +6 -0
  31. package/examples/unsafe-rules/.cursor/rules/always-4.mdc +6 -0
  32. package/examples/unsafe-rules/.cursor/rules/always-5.mdc +6 -0
  33. package/examples/unsafe-rules/.cursor/rules/always-6.mdc +6 -0
  34. package/examples/unsafe-rules/.cursor/rules/duplicate-a.mdc +6 -0
  35. package/examples/unsafe-rules/.cursor/rules/duplicate-b.mdc +7 -0
  36. package/examples/unsafe-rules/.cursor/rules/empty.mdc +5 -0
  37. package/examples/unsafe-rules/.cursor/rules/invalid-fields.mdc +7 -0
  38. package/examples/unsafe-rules/.cursor/rules/invalid-yaml.mdc +6 -0
  39. package/examples/unsafe-rules/.cursor/rules/no-frontmatter.mdc +1 -0
  40. package/examples/unsafe-rules/.cursorrules +1 -0
  41. package/examples/unsafe-rules/AGENTS.md +4 -0
  42. package/examples/unsafe-rules/CLAUDE.md +13 -0
  43. package/examples/unsafe-rules/GEMINI.md +3 -0
  44. package/package.json +26 -0
  45. package/src/cli.ts +104 -0
  46. package/src/index.ts +5 -0
  47. package/src/rules/report.ts +83 -0
  48. package/src/rules/scan.ts +544 -0
  49. package/src/rules/types.ts +36 -0
  50. package/test/scanner.test.mjs +136 -0
  51. package/tsconfig.json +17 -0
package/.gitattributes ADDED
@@ -0,0 +1,5 @@
1
+ * text=auto eol=lf
2
+
3
+ *.bat text eol=crlf
4
+ *.cmd text eol=crlf
5
+ *.ps1 text eol=crlf
@@ -0,0 +1,34 @@
1
+ name: CI
2
+
3
+ on:
4
+ push:
5
+ pull_request:
6
+
7
+ permissions:
8
+ contents: read
9
+
10
+ jobs:
11
+ test:
12
+ runs-on: ubuntu-latest
13
+
14
+ steps:
15
+ - name: Checkout repository
16
+ uses: actions/checkout@v4
17
+
18
+ - name: Set up Node.js
19
+ uses: actions/setup-node@v4
20
+ with:
21
+ node-version: 20
22
+ cache: npm
23
+
24
+ - name: Install dependencies
25
+ run: npm ci
26
+
27
+ - name: Run tests
28
+ run: npm test
29
+
30
+ - name: Run typecheck
31
+ run: npm run typecheck
32
+
33
+ - name: Build
34
+ run: npm run build
package/CHANGELOG.md ADDED
@@ -0,0 +1,13 @@
1
+ # Changelog
2
+
3
+ All notable changes to AgentSafe will be documented in this file.
4
+
5
+ ## [0.1.0] - 2026-07-13
6
+
7
+ ### Added
8
+
9
+ - Initial AI Rules Scanner.
10
+ - Static scanning for Cursor `.mdc` rules with YAML frontmatter.
11
+ - Scanning for `AGENTS.md`, `CLAUDE.md`, `GEMINI.md`, and `.cursorrules`.
12
+ - Redaction of possible secret values from reports.
13
+ - JSON, Markdown, and text report formats.
@@ -0,0 +1,23 @@
1
+ # Contributing
2
+
3
+ Thank you for helping improve AgentSafe.
4
+
5
+ ## Development Checks
6
+
7
+ Before opening a pull request, run:
8
+
9
+ ```shell
10
+ npm test
11
+ npm run typecheck
12
+ npm run build
13
+ ```
14
+
15
+ ## Project Principles
16
+
17
+ Contributions must preserve AgentSafe's offline-first, privacy-first design:
18
+
19
+ - do not add telemetry;
20
+ - do not add network calls or external API dependencies;
21
+ - do not execute scanned files or workspace code;
22
+ - do not execute MCP commands or start subprocesses from scan results;
23
+ - keep changes focused, small, and covered by tests where appropriate.
package/LICENSE ADDED
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2026 mewsyy
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
package/README.md ADDED
@@ -0,0 +1,128 @@
1
+ # AgentSafe
2
+
3
+ [![CI](https://github.com/mewsyy/agentsafe/actions/workflows/ci.yml/badge.svg)](https://github.com/mewsyy/agentsafe/actions/workflows/ci.yml)
4
+ [![License: MIT](https://img.shields.io/badge/License-MIT-blue.svg)](LICENSE)
5
+ [![Node.js 20+](https://img.shields.io/badge/Node.js-20%2B-43853d.svg)](https://nodejs.org/)
6
+
7
+ **Find risky, vague, or secret-bearing AI coding rules before an agent reads them.**
8
+
9
+ AgentSafe is an offline-first, privacy-first safety and hygiene toolkit for AI coding workspaces. It uses static analysis to inspect AI instruction files without running their contents.
10
+
11
+ > **Warning:** AgentSafe never executes scanned files, MCP commands, subprocesses, or workspace code.
12
+
13
+ ## Quick Start
14
+
15
+ Requires Node.js 20 or newer.
16
+
17
+ ```shell
18
+ git clone https://github.com/mewsyy/agentsafe.git
19
+ cd agentsafe
20
+ npm ci
21
+ npm run build
22
+ node dist/index.js rules scan .
23
+ ```
24
+
25
+ Use `--json` or `--markdown` to select a report format:
26
+
27
+ ```shell
28
+ node dist/index.js rules scan . --markdown
29
+ ```
30
+
31
+ ## Example Output
32
+
33
+ ```text
34
+ AgentSafe Rules Scan
35
+ Files scanned: 2
36
+ Findings: 2 (1 high, 1 warnings)
37
+
38
+ [HIGH] CLAUDE.md:8 openai-key: Possible OpenAI API key detected; value omitted.
39
+ [WARNING] .cursor/rules/general.mdc:1 vague-instruction: Rule contains a vague instruction without a concrete example.
40
+ ```
41
+
42
+ Secret values and source lines are omitted from reports.
43
+
44
+ ## Privacy Guarantees
45
+
46
+ - Static analysis only.
47
+ - No scanned files or workspace code are executed.
48
+ - No MCP commands or subprocesses are executed.
49
+ - No external APIs or network calls are used while scanning.
50
+ - No files or findings are uploaded.
51
+ - No telemetry is collected.
52
+ - No scan data is stored in a database.
53
+
54
+ ## v0.1: AI Rules Scanner
55
+
56
+ Version 0.1 scans these workspace files when present:
57
+
58
+ - `.cursor/rules/*.mdc`
59
+ - `AGENTS.md`
60
+ - `CLAUDE.md`
61
+ - `GEMINI.md`
62
+ - `.cursorrules`
63
+
64
+ The scanner parses YAML frontmatter in Cursor `.mdc` files and validates `description`, `globs`, and `alwaysApply`. It reports:
65
+
66
+ - missing or invalid frontmatter;
67
+ - empty rule bodies;
68
+ - very long rules that are always applied;
69
+ - duplicate glob patterns;
70
+ - too many always-applied rules;
71
+ - vague instructions without concrete examples;
72
+ - suspicious instructions involving secrets, environment data, exfiltration, or disabled safety;
73
+ - possible OpenAI, Anthropic, GitHub, AWS, and generic API credentials.
74
+
75
+ Possible secret values are never included in reports. Reports contain only the finding type, relative file path, line number, and a short explanation.
76
+
77
+ ## Usage
78
+
79
+ ```shell
80
+ npm install
81
+ npm run build
82
+ ```
83
+
84
+ Scan the current directory:
85
+
86
+ ```shell
87
+ agentsafe rules scan
88
+ ```
89
+
90
+ Scan a specific workspace:
91
+
92
+ ```shell
93
+ agentsafe rules scan path/to/workspace
94
+ ```
95
+
96
+ Generate machine-readable JSON or a Markdown report:
97
+
98
+ ```shell
99
+ agentsafe rules scan --json
100
+ agentsafe rules scan --markdown
101
+ ```
102
+
103
+ Findings do not cause a non-zero exit code. Invalid arguments and scan failures exit with code `1`.
104
+
105
+ To inspect the included unsafe example without executing any of its contents:
106
+
107
+ ```shell
108
+ npm run scan:example
109
+ ```
110
+
111
+ ## Development
112
+
113
+ ```shell
114
+ npm test
115
+ npm run typecheck
116
+ npm run build
117
+ ```
118
+
119
+ ## Roadmap
120
+
121
+ - **v0.1:** static scanning for Cursor and other AI rule files.
122
+ - **v0.2:** static scanning for MCP configuration and command definitions.
123
+
124
+ The v0.2 MCP scanner will remain static-only. It will inspect configuration as text and structured data without starting servers, executing commands, or using the network.
125
+
126
+ ## Limits
127
+
128
+ AgentSafe uses conservative heuristics. A clean report does not prove that a workspace is safe, and a finding should be reviewed in context. All analysis remains on the local machine.
package/SECURITY.md ADDED
@@ -0,0 +1,22 @@
1
+ # Security Policy
2
+
3
+ ## Security Model
4
+
5
+ AgentSafe is a static-only, offline-first analysis tool. It reads supported rule files as text and structured data, then reports local findings.
6
+
7
+ AgentSafe does not:
8
+
9
+ - execute scanned files or workspace code;
10
+ - execute MCP server commands;
11
+ - start subprocesses from scan results;
12
+ - upload user files or scan results;
13
+ - call external APIs or require network access while scanning;
14
+ - collect telemetry.
15
+
16
+ Possible secret values are omitted from reports. Findings identify the secret type, relative file path, and line number without reproducing the detected value.
17
+
18
+ ## Reporting A Security Issue
19
+
20
+ For now, report security issues through the [GitHub issue tracker](https://github.com/mewsyy/agentsafe/issues).
21
+
22
+ GitHub issues are public. Do not include real credentials, private source code, personal data, or other sensitive information. Use redacted examples and provide the smallest reproduction needed to explain the issue.
package/dist/cli.d.ts ADDED
@@ -0,0 +1,7 @@
1
+ #!/usr/bin/env node
2
+ interface CliOutput {
3
+ stdout(value: string): void;
4
+ stderr(value: string): void;
5
+ }
6
+ export declare function runCli(args: string[], cwd?: string, output?: CliOutput): Promise<number>;
7
+ export {};
package/dist/cli.js ADDED
@@ -0,0 +1,77 @@
1
+ #!/usr/bin/env node
2
+ import { pathToFileURL } from "node:url";
3
+ import { resolve } from "node:path";
4
+ import { formatJsonReport, formatMarkdownReport, formatTextReport, } from "./rules/report.js";
5
+ import { scanRules } from "./rules/scan.js";
6
+ const usage = `Usage:
7
+ agentsafe rules scan [directory] [--json | --markdown]
8
+
9
+ Scans AI rule files using local, static analysis only.
10
+ `;
11
+ export async function runCli(args, cwd = process.cwd(), output = {
12
+ stdout: (value) => process.stdout.write(value),
13
+ stderr: (value) => process.stderr.write(value),
14
+ }) {
15
+ if (args.includes("--help") || args.includes("-h")) {
16
+ output.stdout(usage);
17
+ return 0;
18
+ }
19
+ let options;
20
+ try {
21
+ options = parseArguments(args);
22
+ }
23
+ catch (error) {
24
+ output.stderr(`${getErrorMessage(error)}\n\n${usage}`);
25
+ return 1;
26
+ }
27
+ try {
28
+ const report = await scanRules(resolve(cwd, options.directory));
29
+ const formatted = options.format === "json"
30
+ ? formatJsonReport(report)
31
+ : options.format === "markdown"
32
+ ? formatMarkdownReport(report)
33
+ : formatTextReport(report);
34
+ output.stdout(formatted);
35
+ return 0;
36
+ }
37
+ catch (error) {
38
+ output.stderr(`AgentSafe scan failed: ${getErrorMessage(error)}\n`);
39
+ return 1;
40
+ }
41
+ }
42
+ function parseArguments(args) {
43
+ if (args[0] !== "rules" || args[1] !== "scan") {
44
+ throw new Error("Unknown command.");
45
+ }
46
+ let format = "text";
47
+ let directory = ".";
48
+ let hasDirectory = false;
49
+ for (const argument of args.slice(2)) {
50
+ if (argument === "--json" || argument === "--markdown") {
51
+ const requestedFormat = argument.slice(2);
52
+ if (format !== "text") {
53
+ throw new Error("Use only one report format flag.");
54
+ }
55
+ format = requestedFormat;
56
+ }
57
+ else if (argument.startsWith("-")) {
58
+ throw new Error(`Unknown option: ${argument}`);
59
+ }
60
+ else if (hasDirectory) {
61
+ throw new Error("Only one scan directory may be provided.");
62
+ }
63
+ else {
64
+ directory = argument;
65
+ hasDirectory = true;
66
+ }
67
+ }
68
+ return { directory, format };
69
+ }
70
+ function getErrorMessage(error) {
71
+ return error instanceof Error ? error.message : "Unknown error.";
72
+ }
73
+ const invokedPath = process.argv[1];
74
+ if (invokedPath && pathToFileURL(invokedPath).href === import.meta.url) {
75
+ process.exitCode = await runCli(process.argv.slice(2));
76
+ }
77
+ //# sourceMappingURL=cli.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"cli.js","sourceRoot":"","sources":["../src/cli.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,2 @@
1
+ #!/usr/bin/env node
2
+ export {};
package/dist/index.js ADDED
@@ -0,0 +1,4 @@
1
+ #!/usr/bin/env node
2
+ import { runCli } from "./cli.js";
3
+ process.exitCode = await runCli(process.argv.slice(2));
4
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":";AAEA,OAAO,EAAE,MAAM,EAAE,MAAM,UAAU,CAAC;AAElC,OAAO,CAAC,QAAQ,GAAG,MAAM,MAAM,CAAC,OAAO,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,CAAC"}
@@ -0,0 +1,4 @@
1
+ import type { ScanReport } from "./types.js";
2
+ export declare function formatJsonReport(report: ScanReport): string;
3
+ export declare function formatMarkdownReport(report: ScanReport): string;
4
+ export declare function formatTextReport(report: ScanReport): string;
@@ -0,0 +1,71 @@
1
+ export function formatJsonReport(report) {
2
+ return `${JSON.stringify(report, null, 2)}\n`;
3
+ }
4
+ export function formatMarkdownReport(report) {
5
+ const lines = [
6
+ "# AgentSafe Rules Scan",
7
+ "",
8
+ `- Target: \`${report.target}\``,
9
+ `- Files scanned: ${report.summary.files}`,
10
+ `- High severity: ${report.summary.high}`,
11
+ `- Warnings: ${report.summary.warnings}`,
12
+ `- Total findings: ${report.summary.total}`,
13
+ "",
14
+ "## Findings",
15
+ "",
16
+ ];
17
+ if (report.findings.length === 0) {
18
+ lines.push("_No findings._");
19
+ }
20
+ else {
21
+ lines.push("| Severity | Rule | Location | Message |");
22
+ lines.push("| --- | --- | --- | --- |");
23
+ for (const finding of report.findings) {
24
+ lines.push(`| ${finding.severity.toUpperCase()} | \`${escapeMarkdown(finding.code)}\` | ${formatMarkdownLocation(finding)} | ${escapeMarkdown(finding.message)} |`);
25
+ }
26
+ }
27
+ lines.push("", "## Scanned Files", "");
28
+ if (report.files.length === 0) {
29
+ lines.push("_No supported rule files found._");
30
+ }
31
+ else {
32
+ for (const file of report.files) {
33
+ lines.push(`- \`${escapeMarkdown(file)}\``);
34
+ }
35
+ }
36
+ return `${lines.join("\n")}\n`;
37
+ }
38
+ export function formatTextReport(report) {
39
+ const lines = [
40
+ "AgentSafe Rules Scan",
41
+ `Files scanned: ${report.summary.files}`,
42
+ `Findings: ${report.summary.total} (${report.summary.high} high, ${report.summary.warnings} warnings)`,
43
+ ];
44
+ if (report.findings.length === 0) {
45
+ lines.push("", "No findings.");
46
+ }
47
+ else {
48
+ lines.push("");
49
+ for (const finding of report.findings) {
50
+ lines.push(`[${finding.severity.toUpperCase()}] ${formatTextLocation(finding)} ${finding.code}: ${finding.message}`);
51
+ }
52
+ }
53
+ return `${lines.join("\n")}\n`;
54
+ }
55
+ function formatMarkdownLocation(finding) {
56
+ if (!finding.path) {
57
+ return "project";
58
+ }
59
+ const location = finding.line ? `${finding.path}:${finding.line}` : finding.path;
60
+ return `\`${escapeMarkdown(location)}\``;
61
+ }
62
+ function formatTextLocation(finding) {
63
+ if (!finding.path) {
64
+ return "project";
65
+ }
66
+ return finding.line ? `${finding.path}:${finding.line}` : finding.path;
67
+ }
68
+ function escapeMarkdown(value) {
69
+ return value.replace(/\\/g, "\\\\").replace(/\|/g, "\\|").replace(/`/g, "\\`");
70
+ }
71
+ //# sourceMappingURL=report.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"report.js","sourceRoot":"","sources":["../../src/rules/report.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,2 @@
1
+ import type { ScanReport } from "./types.js";
2
+ export declare function scanRules(rootInput: string): Promise<ScanReport>;