dravix-agent 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 (208) hide show
  1. package/.claude/settings.example.json +30 -0
  2. package/ARCHITECTURE.md +410 -0
  3. package/LICENSE +21 -0
  4. package/README.md +153 -0
  5. package/ROADMAP.md +117 -0
  6. package/data/vulnkb.json +666 -0
  7. package/dist/bin/aegis.d.ts +3 -0
  8. package/dist/bin/aegis.d.ts.map +1 -0
  9. package/dist/bin/aegis.js +489 -0
  10. package/dist/bin/aegis.js.map +1 -0
  11. package/dist/cache.d.ts +9 -0
  12. package/dist/cache.d.ts.map +1 -0
  13. package/dist/cache.js +146 -0
  14. package/dist/cache.js.map +1 -0
  15. package/dist/engines/ai-sinks.d.ts +52 -0
  16. package/dist/engines/ai-sinks.d.ts.map +1 -0
  17. package/dist/engines/ai-sinks.js +204 -0
  18. package/dist/engines/ai-sinks.js.map +1 -0
  19. package/dist/engines/eslint.d.ts +9 -0
  20. package/dist/engines/eslint.d.ts.map +1 -0
  21. package/dist/engines/eslint.js +245 -0
  22. package/dist/engines/eslint.js.map +1 -0
  23. package/dist/engines/joern.d.ts +3 -0
  24. package/dist/engines/joern.d.ts.map +1 -0
  25. package/dist/engines/joern.js +98 -0
  26. package/dist/engines/joern.js.map +1 -0
  27. package/dist/engines/js-sinks.d.ts +70 -0
  28. package/dist/engines/js-sinks.d.ts.map +1 -0
  29. package/dist/engines/js-sinks.js +370 -0
  30. package/dist/engines/js-sinks.js.map +1 -0
  31. package/dist/engines/llm-critic.d.ts +130 -0
  32. package/dist/engines/llm-critic.d.ts.map +1 -0
  33. package/dist/engines/llm-critic.js +551 -0
  34. package/dist/engines/llm-critic.js.map +1 -0
  35. package/dist/engines/pragma.d.ts +20 -0
  36. package/dist/engines/pragma.d.ts.map +1 -0
  37. package/dist/engines/pragma.js +83 -0
  38. package/dist/engines/pragma.js.map +1 -0
  39. package/dist/engines/property-test.d.ts +3 -0
  40. package/dist/engines/property-test.d.ts.map +1 -0
  41. package/dist/engines/property-test.js +134 -0
  42. package/dist/engines/property-test.js.map +1 -0
  43. package/dist/engines/pyright.d.ts +10 -0
  44. package/dist/engines/pyright.d.ts.map +1 -0
  45. package/dist/engines/pyright.js +143 -0
  46. package/dist/engines/pyright.js.map +1 -0
  47. package/dist/engines/pysa.d.ts +3 -0
  48. package/dist/engines/pysa.d.ts.map +1 -0
  49. package/dist/engines/pysa.js +83 -0
  50. package/dist/engines/pysa.js.map +1 -0
  51. package/dist/engines/python-sinks.d.ts +82 -0
  52. package/dist/engines/python-sinks.d.ts.map +1 -0
  53. package/dist/engines/python-sinks.js +459 -0
  54. package/dist/engines/python-sinks.js.map +1 -0
  55. package/dist/engines/registry.d.ts +26 -0
  56. package/dist/engines/registry.d.ts.map +1 -0
  57. package/dist/engines/registry.js +70 -0
  58. package/dist/engines/registry.js.map +1 -0
  59. package/dist/engines/secret-scan.d.ts +22 -0
  60. package/dist/engines/secret-scan.d.ts.map +1 -0
  61. package/dist/engines/secret-scan.js +179 -0
  62. package/dist/engines/secret-scan.js.map +1 -0
  63. package/dist/engines/semgrep.d.ts +10 -0
  64. package/dist/engines/semgrep.d.ts.map +1 -0
  65. package/dist/engines/semgrep.js +200 -0
  66. package/dist/engines/semgrep.js.map +1 -0
  67. package/dist/engines/treesitter.d.ts +18 -0
  68. package/dist/engines/treesitter.d.ts.map +1 -0
  69. package/dist/engines/treesitter.js +135 -0
  70. package/dist/engines/treesitter.js.map +1 -0
  71. package/dist/engines/tsc.d.ts +10 -0
  72. package/dist/engines/tsc.d.ts.map +1 -0
  73. package/dist/engines/tsc.js +142 -0
  74. package/dist/engines/tsc.js.map +1 -0
  75. package/dist/engines/types.d.ts +47 -0
  76. package/dist/engines/types.d.ts.map +1 -0
  77. package/dist/engines/types.js +27 -0
  78. package/dist/engines/types.js.map +1 -0
  79. package/dist/findings.d.ts +121 -0
  80. package/dist/findings.d.ts.map +1 -0
  81. package/dist/findings.js +98 -0
  82. package/dist/findings.js.map +1 -0
  83. package/dist/hooks/claude-code.d.ts +3 -0
  84. package/dist/hooks/claude-code.d.ts.map +1 -0
  85. package/dist/hooks/claude-code.js +187 -0
  86. package/dist/hooks/claude-code.js.map +1 -0
  87. package/dist/index/context.d.ts +127 -0
  88. package/dist/index/context.d.ts.map +1 -0
  89. package/dist/index/context.js +267 -0
  90. package/dist/index/context.js.map +1 -0
  91. package/dist/index/embeddings.d.ts +68 -0
  92. package/dist/index/embeddings.d.ts.map +1 -0
  93. package/dist/index/embeddings.js +570 -0
  94. package/dist/index/embeddings.js.map +1 -0
  95. package/dist/index/graph_routing.d.ts +36 -0
  96. package/dist/index/graph_routing.d.ts.map +1 -0
  97. package/dist/index/graph_routing.js +170 -0
  98. package/dist/index/graph_routing.js.map +1 -0
  99. package/dist/index/joern.d.ts +76 -0
  100. package/dist/index/joern.d.ts.map +1 -0
  101. package/dist/index/joern.js +782 -0
  102. package/dist/index/joern.js.map +1 -0
  103. package/dist/index/property-test.d.ts +88 -0
  104. package/dist/index/property-test.d.ts.map +1 -0
  105. package/dist/index/property-test.js +466 -0
  106. package/dist/index/property-test.js.map +1 -0
  107. package/dist/index/proto/scip.proto +897 -0
  108. package/dist/index/pysa.d.ts +91 -0
  109. package/dist/index/pysa.d.ts.map +1 -0
  110. package/dist/index/pysa.js +617 -0
  111. package/dist/index/pysa.js.map +1 -0
  112. package/dist/index/scip.d.ts +76 -0
  113. package/dist/index/scip.d.ts.map +1 -0
  114. package/dist/index/scip.js +541 -0
  115. package/dist/index/scip.js.map +1 -0
  116. package/dist/index/vulrag.d.ts +86 -0
  117. package/dist/index/vulrag.d.ts.map +1 -0
  118. package/dist/index/vulrag.js +242 -0
  119. package/dist/index/vulrag.js.map +1 -0
  120. package/dist/index.d.ts +9 -0
  121. package/dist/index.d.ts.map +1 -0
  122. package/dist/index.js +8 -0
  123. package/dist/index.js.map +1 -0
  124. package/dist/install/claude-code.d.ts +31 -0
  125. package/dist/install/claude-code.d.ts.map +1 -0
  126. package/dist/install/claude-code.js +447 -0
  127. package/dist/install/claude-code.js.map +1 -0
  128. package/dist/lang.d.ts +5 -0
  129. package/dist/lang.d.ts.map +1 -0
  130. package/dist/lang.js +52 -0
  131. package/dist/lang.js.map +1 -0
  132. package/dist/learning/suppressions.d.ts +70 -0
  133. package/dist/learning/suppressions.d.ts.map +1 -0
  134. package/dist/learning/suppressions.js +179 -0
  135. package/dist/learning/suppressions.js.map +1 -0
  136. package/dist/mcp/server.d.ts +2 -0
  137. package/dist/mcp/server.d.ts.map +1 -0
  138. package/dist/mcp/server.js +187 -0
  139. package/dist/mcp/server.js.map +1 -0
  140. package/dist/mcp/tools/explain.d.ts +58 -0
  141. package/dist/mcp/tools/explain.d.ts.map +1 -0
  142. package/dist/mcp/tools/explain.js +60 -0
  143. package/dist/mcp/tools/explain.js.map +1 -0
  144. package/dist/mcp/tools/precheck.d.ts +29 -0
  145. package/dist/mcp/tools/precheck.d.ts.map +1 -0
  146. package/dist/mcp/tools/precheck.js +42 -0
  147. package/dist/mcp/tools/precheck.js.map +1 -0
  148. package/dist/mcp/tools/validate.d.ts +73 -0
  149. package/dist/mcp/tools/validate.d.ts.map +1 -0
  150. package/dist/mcp/tools/validate.js +66 -0
  151. package/dist/mcp/tools/validate.js.map +1 -0
  152. package/dist/mcp/warm.d.ts +88 -0
  153. package/dist/mcp/warm.d.ts.map +1 -0
  154. package/dist/mcp/warm.js +331 -0
  155. package/dist/mcp/warm.js.map +1 -0
  156. package/dist/orchestrator.d.ts +46 -0
  157. package/dist/orchestrator.d.ts.map +1 -0
  158. package/dist/orchestrator.js +596 -0
  159. package/dist/orchestrator.js.map +1 -0
  160. package/dist/policy.d.ts +51 -0
  161. package/dist/policy.d.ts.map +1 -0
  162. package/dist/policy.js +201 -0
  163. package/dist/policy.js.map +1 -0
  164. package/dist/risk.d.ts +31 -0
  165. package/dist/risk.d.ts.map +1 -0
  166. package/dist/risk.js +92 -0
  167. package/dist/risk.js.map +1 -0
  168. package/dist/stats.d.ts +72 -0
  169. package/dist/stats.d.ts.map +1 -0
  170. package/dist/stats.js +217 -0
  171. package/dist/stats.js.map +1 -0
  172. package/dist/telemetry/collector.d.ts +10 -0
  173. package/dist/telemetry/collector.d.ts.map +1 -0
  174. package/dist/telemetry/collector.js +75 -0
  175. package/dist/telemetry/collector.js.map +1 -0
  176. package/dist/telemetry/consent.d.ts +9 -0
  177. package/dist/telemetry/consent.d.ts.map +1 -0
  178. package/dist/telemetry/consent.js +42 -0
  179. package/dist/telemetry/consent.js.map +1 -0
  180. package/dist/telemetry/installation.d.ts +2 -0
  181. package/dist/telemetry/installation.d.ts.map +1 -0
  182. package/dist/telemetry/installation.js +32 -0
  183. package/dist/telemetry/installation.js.map +1 -0
  184. package/dist/telemetry/sanitizer.d.ts +5 -0
  185. package/dist/telemetry/sanitizer.d.ts.map +1 -0
  186. package/dist/telemetry/sanitizer.js +60 -0
  187. package/dist/telemetry/sanitizer.js.map +1 -0
  188. package/dist/telemetry/types.d.ts +39 -0
  189. package/dist/telemetry/types.d.ts.map +1 -0
  190. package/dist/telemetry/types.js +4 -0
  191. package/dist/telemetry/types.js.map +1 -0
  192. package/dist/telemetry/uploader.d.ts +12 -0
  193. package/dist/telemetry/uploader.d.ts.map +1 -0
  194. package/dist/telemetry/uploader.js +92 -0
  195. package/dist/telemetry/uploader.js.map +1 -0
  196. package/dist/util/logger.d.ts +19 -0
  197. package/dist/util/logger.d.ts.map +1 -0
  198. package/dist/util/logger.js +58 -0
  199. package/dist/util/logger.js.map +1 -0
  200. package/dist/util/safe-paths.d.ts +8 -0
  201. package/dist/util/safe-paths.d.ts.map +1 -0
  202. package/dist/util/safe-paths.js +102 -0
  203. package/dist/util/safe-paths.js.map +1 -0
  204. package/dist/util/subprocess.d.ts +32 -0
  205. package/dist/util/subprocess.d.ts.map +1 -0
  206. package/dist/util/subprocess.js +137 -0
  207. package/dist/util/subprocess.js.map +1 -0
  208. package/package.json +93 -0
@@ -0,0 +1,179 @@
1
+ /**
2
+ * Suppression learning — append-only per-project store of dismissed findings.
3
+ *
4
+ * Layout: ``<project_root>/.aegis/suppressions.jsonl`` — one JSON line per
5
+ * suppression event. We keep history (rather than overwriting) so the user
6
+ * can audit who-suppressed-what-and-when via simple text tools.
7
+ *
8
+ * Operations:
9
+ * suppress(finding_id, reason, expires_at?) → append an `add` entry
10
+ * unsuppress(finding_id) → append a `remove` entry
11
+ * list() → fold the log into the
12
+ * currently-active set
13
+ * isActive(finding_id) → fast check
14
+ *
15
+ * The log is folded each time `list()` is called; for the realtime gate
16
+ * we cache the active set in `_activeCache` keyed by project root +
17
+ * mtime. The cache invalidates as soon as the file changes.
18
+ *
19
+ * Expiry: an entry's ``expires_at`` is an ISO timestamp; when the wall
20
+ * clock passes it, the suppression is treated as removed automatically
21
+ * (no log rewrite needed). Useful for "snooze this finding for 7 days".
22
+ *
23
+ * What this is NOT (yet): an ML / pattern-based suppression learner.
24
+ * Phase 4 (out of V2-13 scope) will learn "the team always dismisses
25
+ * SECRET-AWS-X in test files" and auto-suppress. v1 is manual via the
26
+ * `aegis suppress` CLI.
27
+ */
28
+ import { appendFileSync, existsSync, mkdirSync, readFileSync, statSync } from "node:fs";
29
+ import { dirname, join } from "node:path";
30
+ import { z } from "zod";
31
+ import { getLogger } from "../util/logger.js";
32
+ const log = getLogger("aegis.suppressions");
33
+ const FINDING_ID_RE = /^[0-9a-f]{16}$/;
34
+ const MAX_REASON_CHARS = 500;
35
+ // ── Schema ────────────────────────────────────────────────────────────────
36
+ const SuppressionEntry = z.object({
37
+ op: z.enum(["add", "remove"]),
38
+ id: z.string().regex(FINDING_ID_RE),
39
+ ts: z.string(), // ISO 8601
40
+ reason: z.string().max(MAX_REASON_CHARS).optional(),
41
+ expires_at: z.string().optional(), // ISO 8601
42
+ who: z.string().max(120).optional(), // OS user, for audit
43
+ });
44
+ const _activeCache = new Map();
45
+ // ── Paths ─────────────────────────────────────────────────────────────────
46
+ export function suppressionsPath(projectRoot) {
47
+ return join(projectRoot, ".aegis", "suppressions.jsonl");
48
+ }
49
+ function ensureDir(p) {
50
+ const d = dirname(p);
51
+ if (!existsSync(d))
52
+ mkdirSync(d, { recursive: true });
53
+ }
54
+ /** Add an `add` event to the log. Idempotent — adding an already-active
55
+ * suppression is a no-op log entry (we still append for audit). */
56
+ export function suppress(projectRoot, findingId, opts) {
57
+ if (!FINDING_ID_RE.test(findingId)) {
58
+ return { ok: false, reason: `invalid finding id (expected 16 hex chars): ${findingId}` };
59
+ }
60
+ const entry = {
61
+ op: "add",
62
+ id: findingId,
63
+ ts: new Date().toISOString(),
64
+ ...(opts?.reason ? { reason: opts.reason.slice(0, MAX_REASON_CHARS) } : {}),
65
+ ...(opts?.expiresAt ? { expires_at: opts.expiresAt } : {}),
66
+ ...(opts?.who ? { who: opts.who.slice(0, 120) } : {}),
67
+ };
68
+ return writeEntry(projectRoot, entry);
69
+ }
70
+ /** Add a `remove` event — the finding will be ALLOWED through again on
71
+ * the next gate run. */
72
+ export function unsuppress(projectRoot, findingId, opts) {
73
+ if (!FINDING_ID_RE.test(findingId)) {
74
+ return { ok: false, reason: `invalid finding id: ${findingId}` };
75
+ }
76
+ const entry = {
77
+ op: "remove",
78
+ id: findingId,
79
+ ts: new Date().toISOString(),
80
+ ...(opts?.reason ? { reason: opts.reason.slice(0, MAX_REASON_CHARS) } : {}),
81
+ ...(opts?.who ? { who: opts.who.slice(0, 120) } : {}),
82
+ };
83
+ return writeEntry(projectRoot, entry);
84
+ }
85
+ function writeEntry(projectRoot, entry) {
86
+ const p = suppressionsPath(projectRoot);
87
+ ensureDir(p);
88
+ try {
89
+ appendFileSync(p, JSON.stringify(entry) + "\n", "utf8");
90
+ // Invalidate the cache for this project — next list() call re-reads.
91
+ _activeCache.delete(projectRoot);
92
+ return { ok: true, entry };
93
+ }
94
+ catch (err) {
95
+ return { ok: false, reason: `write failed: ${String(err)}` };
96
+ }
97
+ }
98
+ // ── Fold the log into the active set ─────────────────────────────────────
99
+ /** Return the currently-active suppressions (folded from the append log,
100
+ * with expired entries dropped). O(1) hit on the per-project cache when
101
+ * the log mtime hasn't changed since the last call. */
102
+ export function listActive(projectRoot) {
103
+ return [...activeMap(projectRoot).values()];
104
+ }
105
+ /** Fast O(1) check used by the orchestrator. Returns true iff the finding
106
+ * id is currently suppressed (added + not removed + not expired). */
107
+ export function isSuppressed(projectRoot, findingId) {
108
+ return activeMap(projectRoot).has(findingId);
109
+ }
110
+ function activeMap(projectRoot) {
111
+ const p = suppressionsPath(projectRoot);
112
+ if (!existsSync(p)) {
113
+ _activeCache.delete(projectRoot);
114
+ return new Map();
115
+ }
116
+ let mtimeMs = 0;
117
+ try {
118
+ mtimeMs = statSync(p).mtimeMs;
119
+ }
120
+ catch {
121
+ return new Map();
122
+ }
123
+ const cached = _activeCache.get(projectRoot);
124
+ if (cached && cached.mtimeMs === mtimeMs) {
125
+ return cached.active;
126
+ }
127
+ // Re-fold the log.
128
+ const active = new Map();
129
+ let raw;
130
+ try {
131
+ raw = readFileSync(p, "utf8");
132
+ }
133
+ catch (err) {
134
+ log.warn("suppressions: read failed", { path: p, err: String(err) });
135
+ return new Map();
136
+ }
137
+ const now = Date.now();
138
+ for (const line of raw.split(/\r?\n/)) {
139
+ const trimmed = line.trim();
140
+ if (!trimmed)
141
+ continue;
142
+ let parsed;
143
+ try {
144
+ const candidate = JSON.parse(trimmed);
145
+ const res = SuppressionEntry.safeParse(candidate);
146
+ if (!res.success)
147
+ continue;
148
+ parsed = res.data;
149
+ }
150
+ catch {
151
+ continue; // skip malformed lines silently
152
+ }
153
+ if (parsed.op === "remove") {
154
+ active.delete(parsed.id);
155
+ continue;
156
+ }
157
+ // op === "add"
158
+ if (parsed.expires_at) {
159
+ const exp = Date.parse(parsed.expires_at);
160
+ if (Number.isFinite(exp) && exp <= now)
161
+ continue; // already expired
162
+ }
163
+ active.set(parsed.id, {
164
+ id: parsed.id,
165
+ added_at: parsed.ts,
166
+ ...(parsed.reason ? { reason: parsed.reason } : {}),
167
+ ...(parsed.expires_at ? { expires_at: parsed.expires_at } : {}),
168
+ ...(parsed.who ? { who: parsed.who } : {}),
169
+ });
170
+ }
171
+ _activeCache.set(projectRoot, { mtimeMs, active });
172
+ return active;
173
+ }
174
+ /** Test-only — wipe the in-memory cache so a test can re-read after
175
+ * writing fresh entries. */
176
+ export function _resetActiveCacheForTests() {
177
+ _activeCache.clear();
178
+ }
179
+ //# sourceMappingURL=suppressions.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"suppressions.js","sourceRoot":"","sources":["../../src/learning/suppressions.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,2 @@
1
+ export declare function startServer(): Promise<void>;
2
+ //# sourceMappingURL=server.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"server.d.ts","sourceRoot":"","sources":["../../src/mcp/server.ts"],"names":[],"mappings":"AA0FA,wBAAsB,WAAW,IAAI,OAAO,CAAC,IAAI,CAAC,CAyGjD"}
@@ -0,0 +1,187 @@
1
+ /**
2
+ * Aegis MCP server (stdio transport).
3
+ *
4
+ * Exposes four tools to the agent (Claude Code / Cursor / Codex / opencode):
5
+ * - precheck_change : fast advisory before the write
6
+ * - validate_edit : authoritative gate after the write
7
+ * - explain_risk : look up a prior decision
8
+ * - aegis_health : warm state + cache hit/miss + availability snapshot
9
+ *
10
+ * The server WARMS at boot (Vul-RAG embed + engine availability probe +
11
+ * SCIP indexer + claude binary discovery) BEFORE announcing itself ready
12
+ * over stdio, so the very first tool call lands on hot caches.
13
+ */
14
+ import { Server } from "@modelcontextprotocol/sdk/server/index.js";
15
+ import { StdioServerTransport } from "@modelcontextprotocol/sdk/server/stdio.js";
16
+ import { CallToolRequestSchema, ListToolsRequestSchema, } from "@modelcontextprotocol/sdk/types.js";
17
+ import { precheckChangeInputSchema, runPrecheckChange } from "./tools/precheck.js";
18
+ import { validateEditInputSchema, runValidateEdit } from "./tools/validate.js";
19
+ import { explainRiskInputSchema, runExplainRisk } from "./tools/explain.js";
20
+ import { warmAtBoot, warmMetrics, refreshAvailability } from "./warm.js";
21
+ import { getLogger } from "../util/logger.js";
22
+ const log = getLogger("aegis.mcp.server");
23
+ const TOOLS = [
24
+ {
25
+ name: "precheck_change",
26
+ description: "Fast (<200 ms) advisory check for a proposed file write. Returns warn/allow; never blocks. Call from PreToolUse.",
27
+ inputSchema: {
28
+ type: "object",
29
+ properties: {
30
+ file_path: { type: "string", description: "Absolute path of the file the agent is about to write." },
31
+ content: { type: "string", description: "Full proposed file content (UTF-8)." },
32
+ project_root: { type: "string", description: "Optional project root for path safety + caching." },
33
+ },
34
+ required: ["file_path", "content"],
35
+ },
36
+ },
37
+ {
38
+ name: "validate_edit",
39
+ description: "Authoritative validation of a file write. Runs all available engines (Semgrep, Pyright/tsc, ESLint, tree-sitter, secret-scan, Joern, Pysa) plus the LLM critic + property test in parallel + sequenced stages. Warm path: in-mem LRU + single-flight dedup. Returns verdict allow|warn|block and a remediation prompt the agent can act on.",
40
+ inputSchema: {
41
+ type: "object",
42
+ properties: {
43
+ file_path: { type: "string", description: "Absolute path of the file (written or about to be written)." },
44
+ content: { type: "string", description: "Full file content (UTF-8)." },
45
+ project_root: { type: "string", description: "Optional project root." },
46
+ },
47
+ required: ["file_path", "content"],
48
+ },
49
+ },
50
+ {
51
+ name: "explain_risk",
52
+ description: "Retrieve prior gate decisions for a file or finding from the local audit log (.aegis/audit.jsonl).",
53
+ inputSchema: {
54
+ type: "object",
55
+ properties: {
56
+ finding_id: {
57
+ type: "string",
58
+ pattern: "^[0-9a-f]{16}$",
59
+ description: "16-hex finding id from a prior validate_edit response.",
60
+ },
61
+ file: { type: "string", description: "Filter audit rows by file path (suffix match)." },
62
+ line: { type: "number", description: "Filter by line number." },
63
+ project_root: { type: "string", description: "Optional project root." },
64
+ limit: { type: "number", description: "Max audit rows returned (default 10)." },
65
+ },
66
+ },
67
+ },
68
+ {
69
+ name: "aegis_health",
70
+ description: "Return the server's warm state, in-mem cache stats, and engine availability snapshot. Optionally refresh availability (`refresh: true`) to re-probe engines installed mid-session.",
71
+ inputSchema: {
72
+ type: "object",
73
+ properties: {
74
+ refresh: { type: "boolean", description: "Re-probe engine availability." },
75
+ },
76
+ },
77
+ },
78
+ ];
79
+ export async function startServer() {
80
+ const tBoot0 = Date.now();
81
+ // Warm BEFORE we even create the server so a fast client probe lands
82
+ // on a hot pipeline. The MCP SDK doesn't expose a "wait for ready" hook
83
+ // pre-connect; doing it here is the closest equivalent.
84
+ let warmState = null;
85
+ try {
86
+ warmState = await warmAtBoot();
87
+ }
88
+ catch (err) {
89
+ log.warn("warm-at-boot failed; server starts cold", { err: String(err) });
90
+ }
91
+ const bootDurationMs = Date.now() - tBoot0;
92
+ log.info("server boot complete", {
93
+ bootDurationMs,
94
+ warmDurationMs: warmState?.durationMs,
95
+ vulRagEntries: warmState?.vulRagEntries,
96
+ engineAvailable: warmState?.engineAvailable,
97
+ claudeBin: warmState?.claudeBin ?? "not_found",
98
+ });
99
+ const server = new Server({ name: "aegis-v2", version: "0.2.0" }, { capabilities: { tools: {} } });
100
+ server.setRequestHandler(ListToolsRequestSchema, async () => ({ tools: TOOLS }));
101
+ server.setRequestHandler(CallToolRequestSchema, async (req) => {
102
+ const { name, arguments: args } = req.params;
103
+ const t0 = Date.now();
104
+ try {
105
+ switch (name) {
106
+ case "precheck_change": {
107
+ const input = precheckChangeInputSchema.parse(args ?? {});
108
+ const out = await runPrecheckChange(input);
109
+ log.debug("tool call ok", { name, ms: Date.now() - t0, verdict: out.verdict });
110
+ return { content: [{ type: "text", text: JSON.stringify(out) }] };
111
+ }
112
+ case "validate_edit": {
113
+ const input = validateEditInputSchema.parse(args ?? {});
114
+ const out = await runValidateEdit(input);
115
+ log.debug("tool call ok", { name, ms: Date.now() - t0, verdict: out.verdict });
116
+ return { content: [{ type: "text", text: JSON.stringify(out) }] };
117
+ }
118
+ case "explain_risk": {
119
+ const input = explainRiskInputSchema.parse(args ?? {});
120
+ const out = runExplainRisk(input);
121
+ return { content: [{ type: "text", text: JSON.stringify(out) }] };
122
+ }
123
+ case "aegis_health": {
124
+ const refresh = args?.refresh === true;
125
+ if (refresh)
126
+ await refreshAvailability();
127
+ const metrics = warmMetrics();
128
+ return {
129
+ content: [
130
+ {
131
+ type: "text",
132
+ text: JSON.stringify({ boot_ms: bootDurationMs, ...metrics }),
133
+ },
134
+ ],
135
+ };
136
+ }
137
+ default:
138
+ return {
139
+ isError: true,
140
+ content: [{ type: "text", text: `unknown tool: ${name}` }],
141
+ };
142
+ }
143
+ }
144
+ catch (err) {
145
+ log.error("tool call failed", { name, err: String(err) });
146
+ return {
147
+ isError: true,
148
+ content: [
149
+ {
150
+ type: "text",
151
+ text: JSON.stringify({
152
+ error: err instanceof Error ? err.message : String(err),
153
+ }),
154
+ },
155
+ ],
156
+ };
157
+ }
158
+ });
159
+ const transport = new StdioServerTransport();
160
+ await server.connect(transport);
161
+ log.info("aegis MCP server ready (stdio)", { warmedMs: bootDurationMs });
162
+ // The stdio transport's stdin listener pins the event loop while the
163
+ // client keeps the connection open. We MUST NOT let the caller's
164
+ // top-level main() return immediately — that would trigger
165
+ // ``process.exit(0)`` and kill the long-running server. Block on a
166
+ // promise that only resolves when stdin closes (client disconnect or
167
+ // EOF) or the transport itself signals close.
168
+ await new Promise((resolve) => {
169
+ const done = () => {
170
+ resolve();
171
+ };
172
+ process.stdin.once("end", done);
173
+ process.stdin.once("close", done);
174
+ // The MCP SDK exposes ``onclose`` on the transport; wire it too in
175
+ // case the client cleanly disconnects without closing the pipe.
176
+ transport.onclose = done;
177
+ });
178
+ log.info("aegis MCP server stopped (stdin closed)");
179
+ }
180
+ // Top-level when invoked via `node ./dist/mcp/server.js`.
181
+ if (import.meta.url === `file://${process.argv[1]}`) {
182
+ startServer().catch((err) => {
183
+ log.error("server crashed", { err: String(err) });
184
+ process.exit(1);
185
+ });
186
+ }
187
+ //# sourceMappingURL=server.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"server.js","sourceRoot":"","sources":["../../src/mcp/server.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,58 @@
1
+ import { z } from "zod";
2
+ export declare const explainRiskInputSchema: z.ZodEffects<z.ZodObject<{
3
+ finding_id: z.ZodOptional<z.ZodString>;
4
+ file: z.ZodOptional<z.ZodString>;
5
+ line: z.ZodOptional<z.ZodNumber>;
6
+ project_root: z.ZodOptional<z.ZodString>;
7
+ limit: z.ZodDefault<z.ZodNumber>;
8
+ }, "strip", z.ZodTypeAny, {
9
+ limit: number;
10
+ file?: string | undefined;
11
+ line?: number | undefined;
12
+ project_root?: string | undefined;
13
+ finding_id?: string | undefined;
14
+ }, {
15
+ file?: string | undefined;
16
+ line?: number | undefined;
17
+ limit?: number | undefined;
18
+ project_root?: string | undefined;
19
+ finding_id?: string | undefined;
20
+ }>, {
21
+ limit: number;
22
+ file?: string | undefined;
23
+ line?: number | undefined;
24
+ project_root?: string | undefined;
25
+ finding_id?: string | undefined;
26
+ }, {
27
+ file?: string | undefined;
28
+ line?: number | undefined;
29
+ limit?: number | undefined;
30
+ project_root?: string | undefined;
31
+ finding_id?: string | undefined;
32
+ }>;
33
+ export type ExplainRiskInput = z.infer<typeof explainRiskInputSchema>;
34
+ export interface AuditRow {
35
+ ts: string;
36
+ file: string;
37
+ lang: string;
38
+ action: "allow" | "warn" | "block";
39
+ duration_ms: number;
40
+ truncated: boolean;
41
+ n_findings: number;
42
+ n_block: number;
43
+ n_warn: number;
44
+ driving: {
45
+ engine: string;
46
+ rule_id: string;
47
+ severity: string;
48
+ confidence: number;
49
+ cwe?: string;
50
+ } | null;
51
+ }
52
+ export interface ExplainRiskOutput {
53
+ matches: AuditRow[];
54
+ total_scanned: number;
55
+ audit_path: string;
56
+ }
57
+ export declare function runExplainRisk(input: ExplainRiskInput): ExplainRiskOutput;
58
+ //# sourceMappingURL=explain.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"explain.d.ts","sourceRoot":"","sources":["../../../src/mcp/tools/explain.ts"],"names":[],"mappings":"AAUA,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAC;AAExB,eAAO,MAAM,sBAAsB;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;EAWhC,CAAC;AAEJ,MAAM,MAAM,gBAAgB,GAAG,CAAC,CAAC,KAAK,CAAC,OAAO,sBAAsB,CAAC,CAAC;AAEtE,MAAM,WAAW,QAAQ;IACvB,EAAE,EAAE,MAAM,CAAC;IACX,IAAI,EAAE,MAAM,CAAC;IACb,IAAI,EAAE,MAAM,CAAC;IACb,MAAM,EAAE,OAAO,GAAG,MAAM,GAAG,OAAO,CAAC;IACnC,WAAW,EAAE,MAAM,CAAC;IACpB,SAAS,EAAE,OAAO,CAAC;IACnB,UAAU,EAAE,MAAM,CAAC;IACnB,OAAO,EAAE,MAAM,CAAC;IAChB,MAAM,EAAE,MAAM,CAAC;IACf,OAAO,EACH;QAAE,MAAM,EAAE,MAAM,CAAC;QAAC,OAAO,EAAE,MAAM,CAAC;QAAC,QAAQ,EAAE,MAAM,CAAC;QAAC,UAAU,EAAE,MAAM,CAAC;QAAC,GAAG,CAAC,EAAE,MAAM,CAAA;KAAE,GACvF,IAAI,CAAC;CACV;AAED,MAAM,WAAW,iBAAiB;IAChC,OAAO,EAAE,QAAQ,EAAE,CAAC;IACpB,aAAa,EAAE,MAAM,CAAC;IACtB,UAAU,EAAE,MAAM,CAAC;CACpB;AAED,wBAAgB,cAAc,CAAC,KAAK,EAAE,gBAAgB,GAAG,iBAAiB,CAmCzE"}
@@ -0,0 +1,60 @@
1
+ /**
2
+ * `explain_risk` — read-only retrieval against the local audit log.
3
+ *
4
+ * Looks up a finding by id (engine+file+line+rule sha) and returns the
5
+ * decision context that surrounded it. Useful for the agent to follow up
6
+ * ("why was this blocked?") or for a human to debug.
7
+ */
8
+ import { readFileSync, existsSync } from "node:fs";
9
+ import { resolve } from "node:path";
10
+ import { z } from "zod";
11
+ export const explainRiskInputSchema = z
12
+ .object({
13
+ finding_id: z.string().regex(/^[0-9a-f]{16}$/).optional(),
14
+ file: z.string().optional(),
15
+ line: z.number().int().positive().optional(),
16
+ project_root: z.string().optional(),
17
+ limit: z.number().int().positive().max(50).default(10),
18
+ })
19
+ .refine((v) => v.finding_id !== undefined || v.file !== undefined, "either finding_id or file must be provided");
20
+ export function runExplainRisk(input) {
21
+ const root = input.project_root ?? process.cwd();
22
+ const auditPath = resolve(root, ".aegis", "audit.jsonl");
23
+ if (!existsSync(auditPath)) {
24
+ return { matches: [], total_scanned: 0, audit_path: auditPath };
25
+ }
26
+ const text = readFileSync(auditPath, "utf8");
27
+ const lines = text.split(/\r?\n/).filter(Boolean);
28
+ const matches = [];
29
+ let scanned = 0;
30
+ // Read most-recent first.
31
+ for (let i = lines.length - 1; i >= 0; i--) {
32
+ scanned++;
33
+ let row;
34
+ try {
35
+ row = JSON.parse(lines[i]);
36
+ }
37
+ catch {
38
+ continue;
39
+ }
40
+ if (input.finding_id) {
41
+ // We don't index findings individually in audit.jsonl (we only log the
42
+ // driving one); approximate match against the driving finding's id-shape
43
+ // via engine+rule. The full per-finding index is Phase 1.
44
+ if (row.driving) {
45
+ const synthId = `${row.driving.engine}/${row.driving.rule_id}`;
46
+ if (synthId.includes(input.finding_id))
47
+ matches.push(row);
48
+ }
49
+ }
50
+ else if (input.file) {
51
+ if (row.file === input.file || row.file.endsWith(input.file)) {
52
+ matches.push(row);
53
+ }
54
+ }
55
+ if (matches.length >= input.limit)
56
+ break;
57
+ }
58
+ return { matches, total_scanned: scanned, audit_path: auditPath };
59
+ }
60
+ //# sourceMappingURL=explain.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"explain.js","sourceRoot":"","sources":["../../../src/mcp/tools/explain.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,29 @@
1
+ /**
2
+ * `precheck_change` — fast advisory (PreToolUse). Never blocks.
3
+ *
4
+ * Runs ONLY the cheap, in-process engines: tree-sitter parse + secret scan +
5
+ * ESLint (if installed and lang matches). No subprocess work — keep it ≤ 50 ms.
6
+ */
7
+ import { z } from "zod";
8
+ export declare const precheckChangeInputSchema: z.ZodObject<{
9
+ file_path: z.ZodString;
10
+ content: z.ZodString;
11
+ project_root: z.ZodOptional<z.ZodString>;
12
+ }, "strip", z.ZodTypeAny, {
13
+ file_path: string;
14
+ content: string;
15
+ project_root?: string | undefined;
16
+ }, {
17
+ file_path: string;
18
+ content: string;
19
+ project_root?: string | undefined;
20
+ }>;
21
+ export type PrecheckChangeInput = z.infer<typeof precheckChangeInputSchema>;
22
+ export interface PrecheckChangeOutput {
23
+ verdict: "allow" | "warn";
24
+ summary: string;
25
+ duration_ms: number;
26
+ reasons: string[];
27
+ }
28
+ export declare function runPrecheckChange(input: PrecheckChangeInput): Promise<PrecheckChangeOutput>;
29
+ //# sourceMappingURL=precheck.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"precheck.d.ts","sourceRoot":"","sources":["../../../src/mcp/tools/precheck.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AACH,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAC;AAKxB,eAAO,MAAM,yBAAyB;;;;;;;;;;;;EAIpC,CAAC;AAEH,MAAM,MAAM,mBAAmB,GAAG,CAAC,CAAC,KAAK,CAAC,OAAO,yBAAyB,CAAC,CAAC;AAE5E,MAAM,WAAW,oBAAoB;IACnC,OAAO,EAAE,OAAO,GAAG,MAAM,CAAC;IAC1B,OAAO,EAAE,MAAM,CAAC;IAChB,WAAW,EAAE,MAAM,CAAC;IACpB,OAAO,EAAE,MAAM,EAAE,CAAC;CACnB;AAKD,wBAAsB,iBAAiB,CAAC,KAAK,EAAE,mBAAmB,GAAG,OAAO,CAAC,oBAAoB,CAAC,CAyBjG"}
@@ -0,0 +1,42 @@
1
+ /**
2
+ * `precheck_change` — fast advisory (PreToolUse). Never blocks.
3
+ *
4
+ * Runs ONLY the cheap, in-process engines: tree-sitter parse + secret scan +
5
+ * ESLint (if installed and lang matches). No subprocess work — keep it ≤ 50 ms.
6
+ */
7
+ import { z } from "zod";
8
+ import { ENGINES } from "../../engines/registry.js";
9
+ import { runGateFast } from "../warm.js";
10
+ export const precheckChangeInputSchema = z.object({
11
+ file_path: z.string().min(1),
12
+ content: z.string(),
13
+ project_root: z.string().optional(),
14
+ });
15
+ // In-process engines only (no subprocess).
16
+ const CHEAP_ENGINE_NAMES = new Set(["secret-scan", "treesitter", "eslint"]);
17
+ export async function runPrecheckChange(input) {
18
+ const cheap = ENGINES.filter((e) => CHEAP_ENGINE_NAMES.has(e.name));
19
+ // Precheck deliberately bypasses the LRU (`noCache: true`) — it's
20
+ // advisory and the user expects "live" feedback even on unchanged
21
+ // content. The warm path still benefits from the availability override.
22
+ const { report } = await runGateFast({
23
+ filePath: input.file_path,
24
+ content: input.content,
25
+ ...(input.project_root !== undefined ? { projectRoot: input.project_root } : {}),
26
+ totalTimeoutMs: 200,
27
+ engines: cheap,
28
+ noCache: true,
29
+ });
30
+ // Precheck is advisory: even a block decision degrades to warn so the agent
31
+ // can choose. `validate_edit` is the authoritative blocker.
32
+ const verdict = report.decision.action === "allow" ? "allow" : "warn";
33
+ return {
34
+ verdict,
35
+ summary: report.decision.summary,
36
+ duration_ms: report.durationMs,
37
+ reasons: report.findings
38
+ .slice(0, 3)
39
+ .map((f) => `${f.engine}/${f.rule_id}: ${f.message.slice(0, 120)}`),
40
+ };
41
+ }
42
+ //# sourceMappingURL=precheck.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"precheck.js","sourceRoot":"","sources":["../../../src/mcp/tools/precheck.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AACH,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAC;AAExB,OAAO,EAAE,OAAO,EAAE,MAAM,2BAA2B,CAAC;AACpD,OAAO,EAAE,WAAW,EAAE,MAAM,YAAY,CAAC;AAEzC,MAAM,CAAC,MAAM,yBAAyB,GAAG,CAAC,CAAC,MAAM,CAAC;IAChD,SAAS,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,GAAG,CAAC,CAAC,CAAC;IAC5B,OAAO,EAAE,CAAC,CAAC,MAAM,EAAE;IACnB,YAAY,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,QAAQ,EAAE;CACpC,CAAC,CAAC;AAWH,2CAA2C;AAC3C,MAAM,kBAAkB,GAAG,IAAI,GAAG,CAAC,CAAC,aAAa,EAAE,YAAY,EAAE,QAAQ,CAAC,CAAC,CAAC;AAE5E,MAAM,CAAC,KAAK,UAAU,iBAAiB,CAAC,KAA0B;IAChE,MAAM,KAAK,GAAG,OAAO,CAAC,MAAM,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,kBAAkB,CAAC,GAAG,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC;IACpE,kEAAkE;IAClE,kEAAkE;IAClE,wEAAwE;IACxE,MAAM,EAAE,MAAM,EAAE,GAAG,MAAM,WAAW,CAAC;QACnC,QAAQ,EAAE,KAAK,CAAC,SAAS;QACzB,OAAO,EAAE,KAAK,CAAC,OAAO;QACtB,GAAG,CAAC,KAAK,CAAC,YAAY,KAAK,SAAS,CAAC,CAAC,CAAC,EAAE,WAAW,EAAE,KAAK,CAAC,YAAY,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC;QAChF,cAAc,EAAE,GAAG;QACnB,OAAO,EAAE,KAAK;QACd,OAAO,EAAE,IAAI;KACd,CAAC,CAAC;IACH,4EAA4E;IAC5E,4DAA4D;IAC5D,MAAM,OAAO,GACX,MAAM,CAAC,QAAQ,CAAC,MAAM,KAAK,OAAO,CAAC,CAAC,CAAC,OAAO,CAAC,CAAC,CAAC,MAAM,CAAC;IACxD,OAAO;QACL,OAAO;QACP,OAAO,EAAE,MAAM,CAAC,QAAQ,CAAC,OAAO;QAChC,WAAW,EAAE,MAAM,CAAC,UAAU;QAC9B,OAAO,EAAE,MAAM,CAAC,QAAQ;aACrB,KAAK,CAAC,CAAC,EAAE,CAAC,CAAC;aACX,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,GAAG,CAAC,CAAC,MAAM,IAAI,CAAC,CAAC,OAAO,KAAK,CAAC,CAAC,OAAO,CAAC,KAAK,CAAC,CAAC,EAAE,GAAG,CAAC,EAAE,CAAC;KACtE,CAAC;AACJ,CAAC"}