milens 0.7.0 → 0.7.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/.agents/skills/adapters/SKILL.md +54 -51
- package/.agents/skills/analyzer/SKILL.md +16 -19
- package/.agents/skills/apps/SKILL.md +60 -68
- package/.agents/skills/docs/SKILL.md +5 -25
- package/.agents/skills/milens/SKILL.md +6 -6
- package/.agents/skills/orchestrator/SKILL.md +8 -10
- package/.agents/skills/parser/SKILL.md +9 -11
- package/.agents/skills/root/SKILL.md +25 -29
- package/.agents/skills/scripts/SKILL.md +13 -16
- package/.agents/skills/security/SKILL.md +4 -9
- package/.agents/skills/server/SKILL.md +28 -25
- package/.agents/skills/store/SKILL.md +17 -21
- package/.agents/skills/test/SKILL.md +14 -19
- package/.agents/skills/ui/SKILL.md +1 -1
- package/README.md +12 -3
- package/adapters/README.md +144 -107
- package/adapters/claude-code/.claude/settings.json.hooks-snippet.json +26 -0
- package/adapters/claude-code/.claude-plugin/plugin.json +11 -0
- package/adapters/claude-code/.mcp.json +9 -0
- package/adapters/codex/.codex/config.toml +3 -0
- package/adapters/copilot/.vscode/mcp.json +10 -0
- package/adapters/cursor/.cursor/mcp.json +9 -0
- package/adapters/cursor/.cursorrules +69 -9
- package/adapters/gemini/.gemini/settings.json +9 -0
- package/dist/agents-md.d.ts +0 -1
- package/dist/agents-md.js +2 -2
- package/dist/agents-md.js.map +1 -1
- package/dist/analyzer/config.d.ts +0 -1
- package/dist/analyzer/engine.d.ts +0 -1
- package/dist/analyzer/engine.js +42 -40
- package/dist/analyzer/engine.js.map +1 -1
- package/dist/analyzer/enrich.d.ts +0 -1
- package/dist/analyzer/enrich.js +13 -0
- package/dist/analyzer/enrich.js.map +1 -1
- package/dist/analyzer/resolver.d.ts +0 -1
- package/dist/analyzer/resolver.js +48 -4
- package/dist/analyzer/resolver.js.map +1 -1
- package/dist/analyzer/review.d.ts +2 -2
- package/dist/analyzer/review.js +7 -59
- package/dist/analyzer/review.js.map +1 -1
- package/dist/analyzer/risk.d.ts +20 -0
- package/dist/analyzer/risk.js +76 -0
- package/dist/analyzer/risk.js.map +1 -0
- package/dist/analyzer/scanner.d.ts +0 -1
- package/dist/analyzer/scanner.js +2 -4
- package/dist/analyzer/scanner.js.map +1 -1
- package/dist/analyzer/scope-resolver.d.ts +0 -1
- package/dist/analyzer/scope-resolver.js +1 -1
- package/dist/analyzer/scope-resolver.js.map +1 -1
- package/dist/build-info.d.ts +2 -0
- package/dist/build-info.js +4 -0
- package/dist/build-info.js.map +1 -0
- package/dist/cli.d.ts +0 -1
- package/dist/cli.js +142 -16
- package/dist/cli.js.map +1 -1
- package/dist/metrics.d.ts +0 -1
- package/dist/orchestrator/orchestrator.d.ts +0 -1
- package/dist/orchestrator/orchestrator.js +16 -1
- package/dist/orchestrator/orchestrator.js.map +1 -1
- package/dist/orchestrator/reporter.d.ts +0 -1
- package/dist/parser/extract.d.ts +0 -1
- package/dist/parser/extract.js +53 -28
- package/dist/parser/extract.js.map +1 -1
- package/dist/parser/lang-css.d.ts +0 -1
- package/dist/parser/lang-go.d.ts +0 -1
- package/dist/parser/lang-html.d.ts +0 -1
- package/dist/parser/lang-java.d.ts +0 -1
- package/dist/parser/lang-js.d.ts +0 -1
- package/dist/parser/lang-md.d.ts +0 -1
- package/dist/parser/lang-php.d.ts +0 -1
- package/dist/parser/lang-py.d.ts +0 -1
- package/dist/parser/lang-ruby.d.ts +0 -1
- package/dist/parser/lang-rust.d.ts +0 -1
- package/dist/parser/lang-ts.d.ts +0 -1
- package/dist/parser/lang-vue.d.ts +0 -1
- package/dist/parser/language-provider.d.ts +0 -1
- package/dist/parser/languages.d.ts +0 -1
- package/dist/parser/loader.d.ts +0 -1
- package/dist/security/deps.d.ts +0 -1
- package/dist/security/rules.d.ts +0 -1
- package/dist/security/rules.js +13 -12
- package/dist/security/rules.js.map +1 -1
- package/dist/server/hooks.d.ts +0 -1
- package/dist/server/mcp-prompts.d.ts +0 -1
- package/dist/server/mcp-prompts.js +509 -523
- package/dist/server/mcp-prompts.js.map +1 -1
- package/dist/server/mcp.d.ts +0 -1
- package/dist/server/mcp.js +156 -655
- package/dist/server/mcp.js.map +1 -1
- package/dist/server/test-plan.d.ts +0 -1
- package/dist/server/tools/deps.d.ts +28 -0
- package/dist/server/tools/deps.js +2 -0
- package/dist/server/tools/deps.js.map +1 -0
- package/dist/server/tools/resources.d.ts +3 -0
- package/dist/server/tools/resources.js +103 -0
- package/dist/server/tools/resources.js.map +1 -0
- package/dist/server/tools/security.d.ts +3 -0
- package/dist/server/tools/security.js +176 -0
- package/dist/server/tools/security.js.map +1 -0
- package/dist/server/tools/session.d.ts +3 -0
- package/dist/server/tools/session.js +140 -0
- package/dist/server/tools/session.js.map +1 -0
- package/dist/server/tools/testing.d.ts +3 -0
- package/dist/server/tools/testing.js +200 -0
- package/dist/server/tools/testing.js.map +1 -0
- package/dist/server/watcher.d.ts +0 -1
- package/dist/server/watcher.js +1 -1
- package/dist/server/watcher.js.map +1 -1
- package/dist/skills.d.ts +0 -1
- package/dist/skills.js +8 -2
- package/dist/skills.js.map +1 -1
- package/dist/store/annotations.d.ts +1 -1
- package/dist/store/annotations.js +14 -3
- package/dist/store/annotations.js.map +1 -1
- package/dist/store/confidence.d.ts +0 -1
- package/dist/store/confidence.js +2 -0
- package/dist/store/confidence.js.map +1 -1
- package/dist/store/db.d.ts +9 -1
- package/dist/store/db.js +87 -20
- package/dist/store/db.js.map +1 -1
- package/dist/store/registry.d.ts +0 -1
- package/dist/store/vectors.d.ts +0 -1
- package/dist/types.d.ts +7 -1
- package/dist/ui/progress.d.ts +0 -1
- package/dist/uninstall.d.ts +0 -1
- package/dist/utils.d.ts +2 -1
- package/dist/utils.js +0 -0
- package/dist/utils.js.map +1 -1
- package/package.json +11 -8
- package/dist/agents-md.d.ts.map +0 -1
- package/dist/analyzer/config.d.ts.map +0 -1
- package/dist/analyzer/engine.d.ts.map +0 -1
- package/dist/analyzer/enrich.d.ts.map +0 -1
- package/dist/analyzer/resolver.d.ts.map +0 -1
- package/dist/analyzer/review.d.ts.map +0 -1
- package/dist/analyzer/scanner.d.ts.map +0 -1
- package/dist/analyzer/scope-resolver.d.ts.map +0 -1
- package/dist/analyzer/testplan.d.ts +0 -59
- package/dist/analyzer/testplan.d.ts.map +0 -1
- package/dist/analyzer/testplan.js +0 -218
- package/dist/analyzer/testplan.js.map +0 -1
- package/dist/cli.d.ts.map +0 -1
- package/dist/metrics.d.ts.map +0 -1
- package/dist/orchestrator/orchestrator.d.ts.map +0 -1
- package/dist/orchestrator/reporter.d.ts.map +0 -1
- package/dist/parser/extract.d.ts.map +0 -1
- package/dist/parser/lang-css.d.ts.map +0 -1
- package/dist/parser/lang-go.d.ts.map +0 -1
- package/dist/parser/lang-html.d.ts.map +0 -1
- package/dist/parser/lang-java.d.ts.map +0 -1
- package/dist/parser/lang-js.d.ts.map +0 -1
- package/dist/parser/lang-md.d.ts.map +0 -1
- package/dist/parser/lang-php.d.ts.map +0 -1
- package/dist/parser/lang-py.d.ts.map +0 -1
- package/dist/parser/lang-ruby.d.ts.map +0 -1
- package/dist/parser/lang-rust.d.ts.map +0 -1
- package/dist/parser/lang-ts.d.ts.map +0 -1
- package/dist/parser/lang-vue.d.ts.map +0 -1
- package/dist/parser/language-provider.d.ts.map +0 -1
- package/dist/parser/languages.d.ts.map +0 -1
- package/dist/parser/loader.d.ts.map +0 -1
- package/dist/security/deps.d.ts.map +0 -1
- package/dist/security/rules.d.ts.map +0 -1
- package/dist/server/hooks.d.ts.map +0 -1
- package/dist/server/mcp-prompts.d.ts.map +0 -1
- package/dist/server/mcp.d.ts.map +0 -1
- package/dist/server/test-plan.d.ts.map +0 -1
- package/dist/server/watcher.d.ts.map +0 -1
- package/dist/skills.d.ts.map +0 -1
- package/dist/store/annotations.d.ts.map +0 -1
- package/dist/store/confidence.d.ts.map +0 -1
- package/dist/store/db.d.ts.map +0 -1
- package/dist/store/registry.d.ts.map +0 -1
- package/dist/store/vectors.d.ts.map +0 -1
- package/dist/types.d.ts.map +0 -1
- package/dist/ui/progress.d.ts.map +0 -1
- package/dist/uninstall.d.ts.map +0 -1
- package/dist/utils.d.ts.map +0 -1
- package/docs/README.md +0 -25
- package/docs/diagram1.svg +0 -1
- package/docs/diagram2.svg +0 -1
- package/docs/diagram3.svg +0 -1
|
@@ -0,0 +1,103 @@
|
|
|
1
|
+
import { ResourceTemplate as Rt } from '@modelcontextprotocol/sdk/server/mcp.js';
|
|
2
|
+
export function registerResources(server, deps) {
|
|
3
|
+
const { getDb, fmtSymbol } = deps;
|
|
4
|
+
server.resource('symbol', new Rt('milens://symbol/{name}', { list: undefined }), { description: 'Symbol context: definition, incoming refs, outgoing deps, role/heat metadata' }, async (uri, { name }) => {
|
|
5
|
+
const { db } = getDb();
|
|
6
|
+
const symbols = db.findSymbolByName(name);
|
|
7
|
+
if (symbols.length === 0) {
|
|
8
|
+
return { contents: [{ uri: uri.href, mimeType: 'text/plain', text: `"${name}" not found.` }] };
|
|
9
|
+
}
|
|
10
|
+
const lines = [];
|
|
11
|
+
for (const sym of symbols) {
|
|
12
|
+
lines.push(`${fmtSymbol(sym, 'L2')}${sym.exported ? ' (exported)' : ''}`);
|
|
13
|
+
const incoming = db.getIncomingLinks(sym.id).filter(l => l.type !== 'contains');
|
|
14
|
+
if (incoming.length > 0) {
|
|
15
|
+
lines.push(`incoming (${incoming.length}):`);
|
|
16
|
+
for (const l of incoming) {
|
|
17
|
+
const from = db.findSymbolById(l.fromId);
|
|
18
|
+
lines.push(` ${l.type}: ${from ? fmtSymbol(from) : l.fromId}`);
|
|
19
|
+
}
|
|
20
|
+
}
|
|
21
|
+
const outgoing = db.getOutgoingLinks(sym.id).filter(l => l.type !== 'contains');
|
|
22
|
+
if (outgoing.length > 0) {
|
|
23
|
+
lines.push(`outgoing (${outgoing.length}):`);
|
|
24
|
+
for (const l of outgoing) {
|
|
25
|
+
const to = db.findSymbolById(l.toId);
|
|
26
|
+
lines.push(` ${l.type}: ${to ? fmtSymbol(to) : l.toId}`);
|
|
27
|
+
}
|
|
28
|
+
}
|
|
29
|
+
lines.push('');
|
|
30
|
+
}
|
|
31
|
+
return { contents: [{ uri: uri.href, mimeType: 'text/plain', text: lines.join('\n') }] };
|
|
32
|
+
});
|
|
33
|
+
server.resource('file-symbols', new Rt('milens://file/{+path}', { list: undefined }), { description: 'All symbols in a file with ref/dep counts' }, async (uri, { path }) => {
|
|
34
|
+
const { db } = getDb();
|
|
35
|
+
const filePath = decodeURIComponent(path);
|
|
36
|
+
const symbols = db.getSymbolsByFile(filePath);
|
|
37
|
+
if (symbols.length === 0) {
|
|
38
|
+
return { contents: [{ uri: uri.href, mimeType: 'text/plain', text: `No symbols in "${filePath}".` }] };
|
|
39
|
+
}
|
|
40
|
+
const lines = [`${filePath}: ${symbols.length} symbols\n`];
|
|
41
|
+
for (const sym of symbols) {
|
|
42
|
+
const incoming = db.getIncomingLinks(sym.id).filter(l => l.type !== 'contains');
|
|
43
|
+
const outgoing = db.getOutgoingLinks(sym.id).filter(l => l.type !== 'contains');
|
|
44
|
+
const exp = sym.exported ? ' (exported)' : '';
|
|
45
|
+
lines.push(`${fmtSymbol(sym, 'L2')}${exp} ← ${incoming.length} refs, → ${outgoing.length} deps`);
|
|
46
|
+
}
|
|
47
|
+
return { contents: [{ uri: uri.href, mimeType: 'text/plain', text: lines.join('\n') }] };
|
|
48
|
+
});
|
|
49
|
+
server.resource('domain', new Rt('milens://domain/{name}', { list: undefined }), { description: 'Domain cluster details: files and top symbols in a domain' }, async (uri, { name }) => {
|
|
50
|
+
const { db } = getDb();
|
|
51
|
+
const domainName = name;
|
|
52
|
+
const allFiles = db.db_getFilesByZone(domainName);
|
|
53
|
+
if (allFiles.length === 0) {
|
|
54
|
+
return { contents: [{ uri: uri.href, mimeType: 'text/plain', text: `Domain "${domainName}" not found.` }] };
|
|
55
|
+
}
|
|
56
|
+
const lines = [`domain: ${domainName} (${allFiles.length} files)\n`];
|
|
57
|
+
let totalSymbols = 0;
|
|
58
|
+
for (const file of allFiles) {
|
|
59
|
+
const syms = db.getSymbolsByFile(file);
|
|
60
|
+
totalSymbols += syms.length;
|
|
61
|
+
const exported = syms.filter(s => s.exported);
|
|
62
|
+
lines.push(`${file}: ${syms.length} symbols (${exported.length} exported)`);
|
|
63
|
+
}
|
|
64
|
+
lines.push(`\ntotal: ${totalSymbols} symbols in ${allFiles.length} files`);
|
|
65
|
+
return { contents: [{ uri: uri.href, mimeType: 'text/plain', text: lines.join('\n') }] };
|
|
66
|
+
});
|
|
67
|
+
server.resource('overview', 'milens://overview', { description: 'Index overview: stats, domains, unresolved, test coverage, staleness' }, async (uri) => {
|
|
68
|
+
const { db, root, lazy } = getDb();
|
|
69
|
+
const stats = lazy.getCachedStats();
|
|
70
|
+
const unresolved = db.getUnresolvedStats();
|
|
71
|
+
const coverage = db.getTestCoverage();
|
|
72
|
+
const domains = lazy.getCachedDomainStats();
|
|
73
|
+
const staleFiles = db.getStaleFiles(24);
|
|
74
|
+
const lines = [
|
|
75
|
+
`repo: ${root}`,
|
|
76
|
+
`symbols: ${stats.symbols}`,
|
|
77
|
+
`links: ${stats.links}`,
|
|
78
|
+
`files: ${stats.files}`,
|
|
79
|
+
];
|
|
80
|
+
if (unresolved.imports > 0 || unresolved.calls > 0) {
|
|
81
|
+
lines.push(`⚠ unresolved (internal): ${unresolved.imports} imports, ${unresolved.calls} calls`);
|
|
82
|
+
}
|
|
83
|
+
if (unresolved.externalImports > 0 || unresolved.externalCalls > 0) {
|
|
84
|
+
lines.push(`external (expected): ${unresolved.externalImports} imports, ${unresolved.externalCalls} calls`);
|
|
85
|
+
}
|
|
86
|
+
if (coverage.testFiles > 0) {
|
|
87
|
+
const pct = coverage.exportedProductionSymbols > 0
|
|
88
|
+
? Math.round(coverage.testedSymbols / coverage.exportedProductionSymbols * 100) : 0;
|
|
89
|
+
lines.push(`test coverage: ${coverage.testedSymbols}/${coverage.exportedProductionSymbols} (${pct}%) from ${coverage.testFiles} test files`);
|
|
90
|
+
}
|
|
91
|
+
if (domains.length > 0) {
|
|
92
|
+
lines.push(`\ndomains (${domains.length}):`);
|
|
93
|
+
for (const d of domains) {
|
|
94
|
+
lines.push(` ${d.domain}: ${d.files} files, ${d.symbols} symbols`);
|
|
95
|
+
}
|
|
96
|
+
}
|
|
97
|
+
if (staleFiles.length > 0) {
|
|
98
|
+
lines.push(`\n⏳ ${staleFiles.length} stale files (>24h)`);
|
|
99
|
+
}
|
|
100
|
+
return { contents: [{ uri: uri.href, mimeType: 'text/plain', text: lines.join('\n') }] };
|
|
101
|
+
});
|
|
102
|
+
}
|
|
103
|
+
//# sourceMappingURL=resources.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"resources.js","sourceRoot":"","sources":["../../../src/server/tools/resources.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,176 @@
|
|
|
1
|
+
import { z } from 'zod';
|
|
2
|
+
import { resolve, relative, join, sep } from 'node:path';
|
|
3
|
+
import { readFileSync, existsSync, mkdirSync, writeFileSync } from 'node:fs';
|
|
4
|
+
import { loadRules } from '../../security/rules.js';
|
|
5
|
+
import { globToRegex } from '../../utils.js';
|
|
6
|
+
/** Resolve `file` under `root` and reject any path that escapes it (path traversal / symlink). */
|
|
7
|
+
function resolveInsideRoot(root, file) {
|
|
8
|
+
const resolvedRoot = resolve(root);
|
|
9
|
+
const fullPath = resolve(resolvedRoot, file);
|
|
10
|
+
if (fullPath !== resolvedRoot && !fullPath.startsWith(resolvedRoot + sep))
|
|
11
|
+
return null;
|
|
12
|
+
return fullPath;
|
|
13
|
+
}
|
|
14
|
+
export function registerSecurityTools(server, deps) {
|
|
15
|
+
const { getDb } = deps;
|
|
16
|
+
server.tool('security_scan', 'Scan codebase for security vulnerabilities using 190+ built-in rules across 25 categories. Replaces multiple manual grep() calls. Categories: secrets, injection, rce, xss, deserialization, ssrf, xxe, path-traversal, file-upload, unicode, dangerous, config, data-leak, crypto, auth, jwt, cors-headers, dependency, cloud, docker, kubernetes, iac, business-logic, api-security, misc, file-access.', {
|
|
17
|
+
scope: z.enum(['all', 'secrets', 'injection', 'rce', 'xss', 'deserialization', 'ssrf', 'xxe', 'path-traversal', 'file-upload', 'unicode', 'dangerous', 'config', 'data-leak', 'crypto', 'auth', 'jwt', 'cors-headers', 'dependency', 'cloud', 'docker', 'kubernetes', 'iac', 'business-logic', 'api-security', 'misc', 'file-access']).optional().default('all').describe('Scan scope'),
|
|
18
|
+
repo: z.string().optional().describe('Repository root path'),
|
|
19
|
+
severity: z.enum(['CRITICAL', 'HIGH', 'MEDIUM', 'LOW']).optional().describe('Minimum severity filter'),
|
|
20
|
+
limit: z.number().optional().default(50).describe('Max findings'),
|
|
21
|
+
}, async ({ scope, repo, severity, limit }) => {
|
|
22
|
+
const { db, root } = getDb(repo);
|
|
23
|
+
const rules = loadRules();
|
|
24
|
+
// Filter rules by scope and severity
|
|
25
|
+
const filtered = rules.filter(r => {
|
|
26
|
+
if (scope !== 'all' && r.category !== scope)
|
|
27
|
+
return false;
|
|
28
|
+
if (severity) {
|
|
29
|
+
const sevOrder = { CRITICAL: 4, HIGH: 3, MEDIUM: 2, LOW: 1 };
|
|
30
|
+
if ((sevOrder[r.severity] || 0) < (sevOrder[severity] || 0))
|
|
31
|
+
return false;
|
|
32
|
+
}
|
|
33
|
+
return r.enabled;
|
|
34
|
+
});
|
|
35
|
+
// Get all source files from the DB
|
|
36
|
+
const symbols = db.getAllSymbols();
|
|
37
|
+
const fileSet = new Set();
|
|
38
|
+
for (const s of symbols) {
|
|
39
|
+
if (s.filePath && !s.filePath.includes('node_modules') && !s.filePath.includes('.git')) {
|
|
40
|
+
fileSet.add(s.filePath);
|
|
41
|
+
}
|
|
42
|
+
}
|
|
43
|
+
const files = [...fileSet].slice(0, 1000); // cap at 1000 files
|
|
44
|
+
const { readFileSync: rfs, existsSync: es } = await import('node:fs');
|
|
45
|
+
const { resolve: resolvePath } = await import('node:path');
|
|
46
|
+
const findings = [];
|
|
47
|
+
const byCategory = {};
|
|
48
|
+
const bySeverity = { CRITICAL: 0, HIGH: 0, MEDIUM: 0, LOW: 0 };
|
|
49
|
+
for (const file of files) {
|
|
50
|
+
const fullPath = resolvePath(root, file);
|
|
51
|
+
if (!es(fullPath))
|
|
52
|
+
continue;
|
|
53
|
+
// Apply excludeGlob from each rule's exclusion pattern
|
|
54
|
+
let shouldExclude = false;
|
|
55
|
+
for (const rule of filtered) {
|
|
56
|
+
if (rule.excludeGlob) {
|
|
57
|
+
const excludePatterns = rule.excludeGlob.split(',');
|
|
58
|
+
for (const pattern of excludePatterns) {
|
|
59
|
+
const regex = globToRegex(pattern.trim());
|
|
60
|
+
if (regex.test(file) || regex.test('/' + file)) {
|
|
61
|
+
shouldExclude = true;
|
|
62
|
+
break;
|
|
63
|
+
}
|
|
64
|
+
}
|
|
65
|
+
}
|
|
66
|
+
if (shouldExclude)
|
|
67
|
+
break;
|
|
68
|
+
}
|
|
69
|
+
if (shouldExclude)
|
|
70
|
+
continue;
|
|
71
|
+
// Skip files that don't match rule fileGlobs (simple check)
|
|
72
|
+
const applicableRules = filtered.filter(r => {
|
|
73
|
+
if (!r.fileGlob)
|
|
74
|
+
return true;
|
|
75
|
+
// Simple glob: just check extension
|
|
76
|
+
const ext = r.fileGlob.replace('**/*.', '').replace('**/*', '');
|
|
77
|
+
return file.endsWith(ext) || r.fileGlob === '**/*';
|
|
78
|
+
});
|
|
79
|
+
if (applicableRules.length === 0)
|
|
80
|
+
continue;
|
|
81
|
+
try {
|
|
82
|
+
const content = rfs(fullPath, 'utf-8');
|
|
83
|
+
const lines = content.split('\n');
|
|
84
|
+
for (const rule of applicableRules) {
|
|
85
|
+
for (const pattern of rule.patterns) {
|
|
86
|
+
let match;
|
|
87
|
+
// Reset regex lastIndex for global patterns
|
|
88
|
+
pattern.lastIndex = 0;
|
|
89
|
+
while ((match = pattern.exec(content)) !== null) {
|
|
90
|
+
const lineNum = content.substring(0, match.index).split('\n').length;
|
|
91
|
+
const ctxStart = Math.max(0, lineNum - 3);
|
|
92
|
+
const ctxEnd = Math.min(lines.length, lineNum + 2);
|
|
93
|
+
const context = lines.slice(ctxStart, ctxEnd).join('\n');
|
|
94
|
+
findings.push({
|
|
95
|
+
ruleId: rule.id,
|
|
96
|
+
category: rule.category,
|
|
97
|
+
severity: rule.severity,
|
|
98
|
+
owasp: rule.owasp,
|
|
99
|
+
file,
|
|
100
|
+
line: lineNum,
|
|
101
|
+
match: match[0].length > 100 ? match[0].slice(0, 97) + '...' : match[0],
|
|
102
|
+
context,
|
|
103
|
+
fix: rule.fix,
|
|
104
|
+
});
|
|
105
|
+
byCategory[rule.category] = (byCategory[rule.category] || 0) + 1;
|
|
106
|
+
bySeverity[rule.severity] = (bySeverity[rule.severity] || 0) + 1;
|
|
107
|
+
}
|
|
108
|
+
}
|
|
109
|
+
}
|
|
110
|
+
}
|
|
111
|
+
catch {
|
|
112
|
+
// Skip unreadable files
|
|
113
|
+
}
|
|
114
|
+
}
|
|
115
|
+
// Calculate security score (100 - deductions)
|
|
116
|
+
const deduction = findings.filter((f) => f.severity === 'CRITICAL').length * 5 +
|
|
117
|
+
findings.filter((f) => f.severity === 'HIGH').length * 2 +
|
|
118
|
+
findings.filter((f) => f.severity === 'MEDIUM').length * 0.5;
|
|
119
|
+
const score = Math.max(0, Math.round(100 - deduction));
|
|
120
|
+
const limited = findings.slice(0, limit);
|
|
121
|
+
return {
|
|
122
|
+
content: [{
|
|
123
|
+
type: 'text',
|
|
124
|
+
text: JSON.stringify({
|
|
125
|
+
summary: {
|
|
126
|
+
totalScanned: files.length,
|
|
127
|
+
findings: findings.length,
|
|
128
|
+
byCategory,
|
|
129
|
+
bySeverity,
|
|
130
|
+
score,
|
|
131
|
+
},
|
|
132
|
+
findings: limited,
|
|
133
|
+
}, null, 2),
|
|
134
|
+
}],
|
|
135
|
+
};
|
|
136
|
+
});
|
|
137
|
+
server.tool('fix_apply', 'Apply a security fix suggestion to a file. Creates a backup before modifying. CRITICAL rules require confirm: true.', {
|
|
138
|
+
ruleId: z.string().describe('Security rule ID (e.g. "hardcoded_secret")'),
|
|
139
|
+
file: z.string().describe('File path relative to repo root'),
|
|
140
|
+
line: z.number().describe('Line number where the issue was found'),
|
|
141
|
+
confirm: z.boolean().optional().default(false).describe('Confirmation required for CRITICAL rules'),
|
|
142
|
+
repo: z.string().optional(),
|
|
143
|
+
}, async ({ ruleId, file, line, confirm, repo }) => {
|
|
144
|
+
const { root } = getDb(repo);
|
|
145
|
+
const rules = loadRules();
|
|
146
|
+
const rule = rules.find(r => r.id === ruleId);
|
|
147
|
+
if (!rule)
|
|
148
|
+
return { content: [{ type: 'text', text: `Rule not found: "${ruleId}"` }] };
|
|
149
|
+
if (rule.severity === 'CRITICAL' && !confirm) {
|
|
150
|
+
return { content: [{ type: 'text', text: `CRITICAL rule "${ruleId}" requires confirmation. Set confirm: true to proceed.` }] };
|
|
151
|
+
}
|
|
152
|
+
const fullPath = resolveInsideRoot(root, file);
|
|
153
|
+
if (!fullPath)
|
|
154
|
+
return { content: [{ type: 'text', text: `Invalid file path: "${file}" resolves outside the repo root.` }] };
|
|
155
|
+
if (!existsSync(fullPath))
|
|
156
|
+
return { content: [{ type: 'text', text: `File not found: ${file}` }] };
|
|
157
|
+
const content = readFileSync(fullPath, 'utf-8');
|
|
158
|
+
const lines = content.split('\n');
|
|
159
|
+
if (line < 1 || line > lines.length)
|
|
160
|
+
return { content: [{ type: 'text', text: `Line ${line} out of range (file has ${lines.length} lines).` }] };
|
|
161
|
+
// Backup original
|
|
162
|
+
const backupDir = join(root, '.milens', 'backups');
|
|
163
|
+
mkdirSync(backupDir, { recursive: true });
|
|
164
|
+
const backupPath = join(backupDir, `${file.replace(/[\\/]/g, '_')}_${Date.now()}.bak`);
|
|
165
|
+
writeFileSync(backupPath, content, 'utf-8');
|
|
166
|
+
// Apply fix: add comment above the affected line with the fix suggestion
|
|
167
|
+
const targetLine = lines[line - 1];
|
|
168
|
+
const indent = targetLine.match(/^(\s*)/)?.[1] ?? '';
|
|
169
|
+
const fixComment = `${indent}// milens(fix): rule=${rule.id} — ${rule.fix ?? 'Review manually'}`;
|
|
170
|
+
lines.splice(line - 1, 0, fixComment);
|
|
171
|
+
const newContent = lines.join('\n');
|
|
172
|
+
writeFileSync(fullPath, newContent, 'utf-8');
|
|
173
|
+
return { content: [{ type: 'text', text: `Fix applied for rule "${ruleId}" at ${file}:${line}\nSeverity: ${rule.severity}\nBackup: ${relative(root, backupPath)}\nFix: ${rule.fix ?? 'Manual review needed'}\n\nAdded fix comment above line ${line}.` }] };
|
|
174
|
+
});
|
|
175
|
+
}
|
|
176
|
+
//# sourceMappingURL=security.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"security.js","sourceRoot":"","sources":["../../../src/server/tools/security.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,140 @@
|
|
|
1
|
+
import { z } from 'zod';
|
|
2
|
+
import { AnnotationStore } from '../../store/annotations.js';
|
|
3
|
+
import { HookManager, defaultOnSessionStart, defaultOnSessionEnd, defaultOnPreCommit, defaultOnFileChange, defaultOnPreCompact, defaultOnPostCompact, } from '../hooks.js';
|
|
4
|
+
import { BUILD_SHA, BUILT_AT } from '../../build-info.js';
|
|
5
|
+
export function registerSessionTools(server, deps) {
|
|
6
|
+
const { getDb, guard, getToolCallCount } = deps;
|
|
7
|
+
server.tool('annotate', 'Record a note about a symbol for future sessions. Use after discovering bugs, patterns, or important caveats.', {
|
|
8
|
+
symbol: z.string(),
|
|
9
|
+
key: z.enum(['note', 'bug', 'security', 'architecture', 'workflow', 'test', 'dependency', 'refactor']),
|
|
10
|
+
value: z.string(),
|
|
11
|
+
agent: z.string().optional(),
|
|
12
|
+
session_id: z.string().optional(),
|
|
13
|
+
confidence: z.number().optional().default(0.5),
|
|
14
|
+
}, async ({ symbol, key, value, agent, session_id, confidence }) => {
|
|
15
|
+
const { db } = getDb();
|
|
16
|
+
const store = new AnnotationStore(db.connection);
|
|
17
|
+
const ann = store.annotate(symbol, key, value, { agent, sessionId: session_id });
|
|
18
|
+
return { content: [{ type: 'text', text: `Annotation saved: ${ann.id}\n symbol: ${ann.symbol}\n key: ${ann.key}\n confidence: ${ann.confidence}` }] };
|
|
19
|
+
});
|
|
20
|
+
server.tool('recall', 'Retrieve annotations saved in previous sessions. Filter by symbol, key, or agent.', {
|
|
21
|
+
symbol: z.string().optional(), key: z.enum(['note', 'bug', 'security', 'architecture', 'workflow', 'test', 'dependency', 'refactor']).optional(),
|
|
22
|
+
agent: z.string().optional(), limit: z.number().optional().default(50),
|
|
23
|
+
}, async ({ symbol, key, agent, limit }) => {
|
|
24
|
+
const { db } = getDb();
|
|
25
|
+
const store = new AnnotationStore(db.connection);
|
|
26
|
+
const results = store.recall({ symbol, key, agent, limit });
|
|
27
|
+
if (results.length === 0)
|
|
28
|
+
return { content: [{ type: 'text', text: 'No annotations found.' }] };
|
|
29
|
+
const lines = [`${results.length} annotation(s):\n`];
|
|
30
|
+
for (const a of results) {
|
|
31
|
+
lines.push(`[${a.key}] ${a.symbol} — ${a.value.slice(0, 120)}`);
|
|
32
|
+
lines.push(` confidence: ${a.confidence.toFixed(1)} | agent: ${a.agent ?? '?'} | ${a.updatedAt}\n`);
|
|
33
|
+
}
|
|
34
|
+
return { content: [{ type: 'text', text: lines.join('\n') }] };
|
|
35
|
+
});
|
|
36
|
+
server.tool('session_start', 'Start a new session. Returns a session ID to use with annotate, session_end, and handoff.', { agent: z.string().describe('Agent name (e.g. vibe-coder, reviewer)') }, async ({ agent }) => {
|
|
37
|
+
const { db, root, dbPath } = getDb();
|
|
38
|
+
const store = new AnnotationStore(db.connection);
|
|
39
|
+
const sessionId = store.sessionStart(agent);
|
|
40
|
+
let hookOutput = '';
|
|
41
|
+
try {
|
|
42
|
+
const manager = new HookManager();
|
|
43
|
+
const config = manager.loadConfig(root);
|
|
44
|
+
if (config.enabled && config.onSessionStart) {
|
|
45
|
+
hookOutput = await defaultOnSessionStart({ agent, sessionId, rootPath: root }, dbPath);
|
|
46
|
+
}
|
|
47
|
+
}
|
|
48
|
+
catch { /* hooks are best-effort */ }
|
|
49
|
+
const text = `Session started: ${sessionId}\nAgent: ${agent}\nBuild: ${BUILD_SHA} (${BUILT_AT})\nUse this ID with annotate() and session_end().`;
|
|
50
|
+
return { content: [{ type: 'text', text: hookOutput ? `${hookOutput}\n\n${text}` : text }] };
|
|
51
|
+
});
|
|
52
|
+
server.tool('session_context', 'Get metadata about a session: annotations, tool calls, duration.', { session_id: z.string() }, async ({ session_id }) => {
|
|
53
|
+
const { db, root } = getDb();
|
|
54
|
+
const store = new AnnotationStore(db.connection);
|
|
55
|
+
const ctx = store.sessionContext(session_id);
|
|
56
|
+
if (!ctx.session)
|
|
57
|
+
return { content: [{ type: 'text', text: `Session "${session_id}" not found.` }] };
|
|
58
|
+
const s = ctx.session;
|
|
59
|
+
const liveCalls = getToolCallCount(root);
|
|
60
|
+
const displayCalls = s.toolCallsCount > 0 ? s.toolCallsCount : liveCalls;
|
|
61
|
+
const lines = [
|
|
62
|
+
`Session: ${s.id}`,
|
|
63
|
+
`Agent: ${s.agent} | Status: ${s.status}`,
|
|
64
|
+
`Started: ${s.startedAt} | Ended: ${s.endedAt ?? 'in progress'}`,
|
|
65
|
+
`Tool calls: ${displayCalls}${s.toolCallsCount === 0 ? ' (live count, resets on restart)' : ''} | Annotations: ${s.annotationsCount}`,
|
|
66
|
+
];
|
|
67
|
+
if (s.context)
|
|
68
|
+
lines.push(`Context: ${s.context}`);
|
|
69
|
+
if (ctx.annotations.length > 0) {
|
|
70
|
+
lines.push(`\nAnnotations (${ctx.annotations.length}):`);
|
|
71
|
+
for (const a of ctx.annotations) {
|
|
72
|
+
lines.push(` [${a.key}] ${a.symbol}: ${a.value.slice(0, 80)}`);
|
|
73
|
+
}
|
|
74
|
+
}
|
|
75
|
+
return { content: [{ type: 'text', text: lines.join('\n') }] };
|
|
76
|
+
});
|
|
77
|
+
server.tool('session_end', 'End a session and record its stats. Shows audit trail: which symbols were safety-checked vs total edit operations. Use at the end of every session.', { session_id: z.string(), status: z.enum(['completed', 'failed']).optional().default('completed') }, async ({ session_id, status }) => {
|
|
78
|
+
const { db, root, dbPath } = getDb();
|
|
79
|
+
const store = new AnnotationStore(db.connection);
|
|
80
|
+
const summary = store.sessionEnd(session_id, status);
|
|
81
|
+
// Audit trail from SessionGuard
|
|
82
|
+
const audit = guard.getAudit(session_id);
|
|
83
|
+
guard.clear(session_id);
|
|
84
|
+
let hookOutput = '';
|
|
85
|
+
try {
|
|
86
|
+
const ctx = store.sessionContext(session_id);
|
|
87
|
+
const manager = new HookManager();
|
|
88
|
+
const config = manager.loadConfig(root);
|
|
89
|
+
if (config.enabled && config.onSessionEnd) {
|
|
90
|
+
hookOutput = await defaultOnSessionEnd({ agent: ctx.session.agent, sessionId: session_id, rootPath: root }, dbPath);
|
|
91
|
+
}
|
|
92
|
+
}
|
|
93
|
+
catch { /* hooks are best-effort */ }
|
|
94
|
+
const lines = [
|
|
95
|
+
`Session ended: ${session_id}`,
|
|
96
|
+
`Status: ${status}`,
|
|
97
|
+
`Annotations: ${summary.annotationCount}`,
|
|
98
|
+
`───`,
|
|
99
|
+
`Audit Trail:`,
|
|
100
|
+
` safety checks performed: ${audit.checked.length}`,
|
|
101
|
+
audit.checked.length > 0 ? ` symbols checked: ${audit.checked.join(', ')}` : ' ⚠ no symbols were checked via guard_edit_check',
|
|
102
|
+
audit.editOps > 0 ? ` edit operations reported: ${audit.editOps}` : null,
|
|
103
|
+
].filter(Boolean);
|
|
104
|
+
const text = lines.join('\n');
|
|
105
|
+
return { content: [{ type: 'text', text: hookOutput ? `${text}\n\n${hookOutput}` : text }] };
|
|
106
|
+
});
|
|
107
|
+
server.tool('handoff', 'Transfer context from one agent session to another. Ends the source session and creates a new one for the target agent.', {
|
|
108
|
+
from_session: z.string(), to_agent: z.string(),
|
|
109
|
+
context: z.string().describe('Summary of what was done, key decisions, and caveats for the next agent'),
|
|
110
|
+
}, async ({ from_session, to_agent, context }) => {
|
|
111
|
+
const { db } = getDb();
|
|
112
|
+
const store = new AnnotationStore(db.connection);
|
|
113
|
+
const result = store.handoff(from_session, to_agent, context);
|
|
114
|
+
return { content: [{ type: 'text', text: `Handoff complete.\nNew session: ${result.newSessionId}\nAgent: ${to_agent}\nAnnotations copied: ${result.annotationsCopied}` }] };
|
|
115
|
+
});
|
|
116
|
+
server.tool('pre_commit_check', 'Run pre-commit risk analysis: detect_changes + review_pr + dead code + coverage gaps. Use before committing.', { repo: z.string().optional().describe('Repository root path') }, async ({ repo }) => {
|
|
117
|
+
const { root } = getDb(repo);
|
|
118
|
+
const report = await defaultOnPreCommit(root);
|
|
119
|
+
return { content: [{ type: 'text', text: report }] };
|
|
120
|
+
});
|
|
121
|
+
server.tool('hook_onFileChange', 'Trigger the onFileChange hook. Call this when files are modified to get impact summary.', {
|
|
122
|
+
files: z.array(z.string()).describe('List of changed file paths'),
|
|
123
|
+
repo: z.string().optional(),
|
|
124
|
+
}, async ({ files, repo }) => {
|
|
125
|
+
const { root } = getDb(repo);
|
|
126
|
+
const report = await defaultOnFileChange(files, root);
|
|
127
|
+
return { content: [{ type: 'text', text: report }] };
|
|
128
|
+
});
|
|
129
|
+
server.tool('hook_preCompact', 'Trigger pre-compaction hook. Saves a metrics snapshot before context window compaction.', { repo: z.string().optional() }, async ({ repo }) => {
|
|
130
|
+
const { root, dbPath } = getDb(repo);
|
|
131
|
+
const report = await defaultOnPreCompact(root, dbPath);
|
|
132
|
+
return { content: [{ type: 'text', text: report }] };
|
|
133
|
+
});
|
|
134
|
+
server.tool('hook_postCompact', 'Trigger post-compaction hook. Recalls annotations to restore context after compaction.', { repo: z.string().optional() }, async ({ repo }) => {
|
|
135
|
+
const { root } = getDb(repo);
|
|
136
|
+
const report = await defaultOnPostCompact(root);
|
|
137
|
+
return { content: [{ type: 'text', text: report }] };
|
|
138
|
+
});
|
|
139
|
+
}
|
|
140
|
+
//# sourceMappingURL=session.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"session.js","sourceRoot":"","sources":["../../../src/server/tools/session.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAC;AACxB,OAAO,EAAE,eAAe,EAAE,MAAM,4BAA4B,CAAC;AAC7D,OAAO,EACL,WAAW,EACX,qBAAqB,EACrB,mBAAmB,EACnB,kBAAkB,EAClB,mBAAmB,EACnB,mBAAmB,EACnB,oBAAoB,GACrB,MAAM,aAAa,CAAC;AAErB,OAAO,EAAE,SAAS,EAAE,QAAQ,EAAE,MAAM,qBAAqB,CAAC;AAE1D,MAAM,UAAU,oBAAoB,CAAC,MAAiB,EAAE,IAAU;IAChE,MAAM,EAAE,KAAK,EAAE,KAAK,EAAE,gBAAgB,EAAE,GAAG,IAAI,CAAC;IAEhD,MAAM,CAAC,IAAI,CACT,UAAU,EACV,+GAA+G,EAC/G;QACE,MAAM,EAAE,CAAC,CAAC,MAAM,EAAE;QAClB,GAAG,EAAE,CAAC,CAAC,IAAI,CAAC,CAAC,MAAM,EAAE,KAAK,EAAE,UAAU,EAAE,cAAc,EAAE,UAAU,EAAE,MAAM,EAAE,YAAY,EAAE,UAAU,CAAC,CAAC;QACtG,KAAK,EAAE,CAAC,CAAC,MAAM,EAAE;QACjB,KAAK,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,QAAQ,EAAE;QAC5B,UAAU,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,QAAQ,EAAE;QACjC,UAAU,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,QAAQ,EAAE,CAAC,OAAO,CAAC,GAAG,CAAC;KAC/C,EACD,KAAK,EAAE,EAAE,MAAM,EAAE,GAAG,EAAE,KAAK,EAAE,KAAK,EAAE,UAAU,EAAE,UAAU,EAAE,EAAE,EAAE;QAC9D,MAAM,EAAE,EAAE,EAAE,GAAG,KAAK,EAAE,CAAC;QACvB,MAAM,KAAK,GAAG,IAAI,eAAe,CAAC,EAAE,CAAC,UAAU,CAAC,CAAC;QACjD,MAAM,GAAG,GAAG,KAAK,CAAC,QAAQ,CAAC,MAAM,EAAE,GAAU,EAAE,KAAK,EAAE,EAAE,KAAK,EAAE,SAAS,EAAE,UAAU,EAAE,CAAC,CAAC;QACxF,OAAO,EAAE,OAAO,EAAE,CAAC,EAAE,IAAI,EAAE,MAAe,EAAE,IAAI,EAAE,qBAAqB,GAAG,CAAC,EAAE,eAAe,GAAG,CAAC,MAAM,YAAY,GAAG,CAAC,GAAG,mBAAmB,GAAG,CAAC,UAAU,EAAE,EAAE,CAAC,EAAE,CAAC;IACpK,CAAC,CACF,CAAC;IAEF,MAAM,CAAC,IAAI,CACT,QAAQ,EACR,mFAAmF,EACnF;QACE,MAAM,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,QAAQ,EAAE,EAAE,GAAG,EAAE,CAAC,CAAC,IAAI,CAAC,CAAC,MAAM,EAAE,KAAK,EAAE,UAAU,EAAE,cAAc,EAAE,UAAU,EAAE,MAAM,EAAE,YAAY,EAAE,UAAU,CAAC,CAAC,CAAC,QAAQ,EAAE;QAChJ,KAAK,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,QAAQ,EAAE,EAAE,KAAK,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,QAAQ,EAAE,CAAC,OAAO,CAAC,EAAE,CAAC;KACvE,EACD,KAAK,EAAE,EAAE,MAAM,EAAE,GAAG,EAAE,KAAK,EAAE,KAAK,EAAE,EAAE,EAAE;QACtC,MAAM,EAAE,EAAE,EAAE,GAAG,KAAK,EAAE,CAAC;QACvB,MAAM,KAAK,GAAG,IAAI,eAAe,CAAC,EAAE,CAAC,UAAU,CAAC,CAAC;QACjD,MAAM,OAAO,GAAG,KAAK,CAAC,MAAM,CAAC,EAAE,MAAM,EAAE,GAAG,EAAE,KAAK,EAAE,KAAK,EAAE,CAAC,CAAC;QAC5D,IAAI,OAAO,CAAC,MAAM,KAAK,CAAC;YAAE,OAAO,EAAE,OAAO,EAAE,CAAC,EAAE,IAAI,EAAE,MAAe,EAAE,IAAI,EAAE,uBAAuB,EAAE,CAAC,EAAE,CAAC;QACzG,MAAM,KAAK,GAAG,CAAC,GAAG,OAAO,CAAC,MAAM,mBAAmB,CAAC,CAAC;QACrD,KAAK,MAAM,CAAC,IAAI,OAAO,EAAE,CAAC;YACxB,KAAK,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC,GAAG,KAAK,CAAC,CAAC,MAAM,MAAM,CAAC,CAAC,KAAK,CAAC,KAAK,CAAC,CAAC,EAAE,GAAG,CAAC,EAAE,CAAC,CAAC;YAChE,KAAK,CAAC,IAAI,CAAC,iBAAiB,CAAC,CAAC,UAAU,CAAC,OAAO,CAAC,CAAC,CAAC,aAAa,CAAC,CAAC,KAAK,IAAI,GAAG,MAAM,CAAC,CAAC,SAAS,IAAI,CAAC,CAAC;QACvG,CAAC;QACD,OAAO,EAAE,OAAO,EAAE,CAAC,EAAE,IAAI,EAAE,MAAe,EAAE,IAAI,EAAE,KAAK,CAAC,IAAI,CAAC,IAAI,CAAC,EAAE,CAAC,EAAE,CAAC;IAC1E,CAAC,CACF,CAAC;IAEF,MAAM,CAAC,IAAI,CACT,eAAe,EACf,2FAA2F,EAC3F,EAAE,KAAK,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,QAAQ,CAAC,wCAAwC,CAAC,EAAE,EACxE,KAAK,EAAE,EAAE,KAAK,EAAE,EAAE,EAAE;QAClB,MAAM,EAAE,EAAE,EAAE,IAAI,EAAE,MAAM,EAAE,GAAG,KAAK,EAAE,CAAC;QACrC,MAAM,KAAK,GAAG,IAAI,eAAe,CAAC,EAAE,CAAC,UAAU,CAAC,CAAC;QACjD,MAAM,SAAS,GAAG,KAAK,CAAC,YAAY,CAAC,KAAK,CAAC,CAAC;QAE5C,IAAI,UAAU,GAAG,EAAE,CAAC;QACpB,IAAI,CAAC;YACH,MAAM,OAAO,GAAG,IAAI,WAAW,EAAE,CAAC;YAClC,MAAM,MAAM,GAAG,OAAO,CAAC,UAAU,CAAC,IAAI,CAAC,CAAC;YACxC,IAAI,MAAM,CAAC,OAAO,IAAI,MAAM,CAAC,cAAc,EAAE,CAAC;gBAC5C,UAAU,GAAG,MAAM,qBAAqB,CAAC,EAAE,KAAK,EAAE,SAAS,EAAE,QAAQ,EAAE,IAAI,EAAE,EAAE,MAAM,CAAC,CAAC;YACzF,CAAC;QACH,CAAC;QAAC,MAAM,CAAC,CAAC,2BAA2B,CAAC,CAAC;QAEvC,MAAM,IAAI,GAAG,oBAAoB,SAAS,YAAY,KAAK,YAAY,SAAS,KAAK,QAAQ,mDAAmD,CAAC;QACjJ,OAAO,EAAE,OAAO,EAAE,CAAC,EAAE,IAAI,EAAE,MAAe,EAAE,IAAI,EAAE,UAAU,CAAC,CAAC,CAAC,GAAG,UAAU,OAAO,IAAI,EAAE,CAAC,CAAC,CAAC,IAAI,EAAE,CAAC,EAAE,CAAC;IACxG,CAAC,CACF,CAAC;IAEF,MAAM,CAAC,IAAI,CACT,iBAAiB,EACjB,kEAAkE,EAClE,EAAE,UAAU,EAAE,CAAC,CAAC,MAAM,EAAE,EAAE,EAC1B,KAAK,EAAE,EAAE,UAAU,EAAE,EAAE,EAAE;QACvB,MAAM,EAAE,EAAE,EAAE,IAAI,EAAE,GAAG,KAAK,EAAE,CAAC;QAC7B,MAAM,KAAK,GAAG,IAAI,eAAe,CAAC,EAAE,CAAC,UAAU,CAAC,CAAC;QACjD,MAAM,GAAG,GAAG,KAAK,CAAC,cAAc,CAAC,UAAU,CAAC,CAAC;QAC7C,IAAI,CAAC,GAAG,CAAC,OAAO;YAAE,OAAO,EAAE,OAAO,EAAE,CAAC,EAAE,IAAI,EAAE,MAAe,EAAE,IAAI,EAAE,YAAY,UAAU,cAAc,EAAE,CAAC,EAAE,CAAC;QAC9G,MAAM,CAAC,GAAG,GAAG,CAAC,OAAO,CAAC;QACtB,MAAM,SAAS,GAAG,gBAAgB,CAAC,IAAI,CAAC,CAAC;QACzC,MAAM,YAAY,GAAG,CAAC,CAAC,cAAc,GAAG,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,cAAc,CAAC,CAAC,CAAC,SAAS,CAAC;QACzE,MAAM,KAAK,GAAG;YACZ,YAAY,CAAC,CAAC,EAAE,EAAE;YAClB,UAAU,CAAC,CAAC,KAAK,cAAc,CAAC,CAAC,MAAM,EAAE;YACzC,YAAY,CAAC,CAAC,SAAS,aAAa,CAAC,CAAC,OAAO,IAAI,aAAa,EAAE;YAChE,eAAe,YAAY,GAAG,CAAC,CAAC,cAAc,KAAK,CAAC,CAAC,CAAC,CAAC,kCAAkC,CAAC,CAAC,CAAC,EAAE,mBAAmB,CAAC,CAAC,gBAAgB,EAAE;SACtI,CAAC;QACF,IAAI,CAAC,CAAC,OAAO;YAAE,KAAK,CAAC,IAAI,CAAC,YAAY,CAAC,CAAC,OAAO,EAAE,CAAC,CAAC;QACnD,IAAI,GAAG,CAAC,WAAW,CAAC,MAAM,GAAG,CAAC,EAAE,CAAC;YAC/B,KAAK,CAAC,IAAI,CAAC,kBAAkB,GAAG,CAAC,WAAW,CAAC,MAAM,IAAI,CAAC,CAAC;YACzD,KAAK,MAAM,CAAC,IAAI,GAAG,CAAC,WAAW,EAAE,CAAC;gBAChC,KAAK,CAAC,IAAI,CAAC,MAAM,CAAC,CAAC,GAAG,KAAK,CAAC,CAAC,MAAM,KAAK,CAAC,CAAC,KAAK,CAAC,KAAK,CAAC,CAAC,EAAE,EAAE,CAAC,EAAE,CAAC,CAAC;YAClE,CAAC;QACH,CAAC;QACD,OAAO,EAAE,OAAO,EAAE,CAAC,EAAE,IAAI,EAAE,MAAe,EAAE,IAAI,EAAE,KAAK,CAAC,IAAI,CAAC,IAAI,CAAC,EAAE,CAAC,EAAE,CAAC;IAC1E,CAAC,CACF,CAAC;IAEF,MAAM,CAAC,IAAI,CACT,aAAa,EACb,qJAAqJ,EACrJ,EAAE,UAAU,EAAE,CAAC,CAAC,MAAM,EAAE,EAAE,MAAM,EAAE,CAAC,CAAC,IAAI,CAAC,CAAC,WAAW,EAAE,QAAQ,CAAC,CAAC,CAAC,QAAQ,EAAE,CAAC,OAAO,CAAC,WAAW,CAAC,EAAE,EACnG,KAAK,EAAE,EAAE,UAAU,EAAE,MAAM,EAAE,EAAE,EAAE;QAC/B,MAAM,EAAE,EAAE,EAAE,IAAI,EAAE,MAAM,EAAE,GAAG,KAAK,EAAE,CAAC;QACrC,MAAM,KAAK,GAAG,IAAI,eAAe,CAAC,EAAE,CAAC,UAAU,CAAC,CAAC;QACjD,MAAM,OAAO,GAAG,KAAK,CAAC,UAAU,CAAC,UAAU,EAAE,MAAM,CAAC,CAAC;QAErD,gCAAgC;QAChC,MAAM,KAAK,GAAG,KAAK,CAAC,QAAQ,CAAC,UAAU,CAAC,CAAC;QACzC,KAAK,CAAC,KAAK,CAAC,UAAU,CAAC,CAAC;QAExB,IAAI,UAAU,GAAG,EAAE,CAAC;QACpB,IAAI,CAAC;YACH,MAAM,GAAG,GAAG,KAAK,CAAC,cAAc,CAAC,UAAU,CAAC,CAAC;YAC7C,MAAM,OAAO,GAAG,IAAI,WAAW,EAAE,CAAC;YAClC,MAAM,MAAM,GAAG,OAAO,CAAC,UAAU,CAAC,IAAI,CAAC,CAAC;YACxC,IAAI,MAAM,CAAC,OAAO,IAAI,MAAM,CAAC,YAAY,EAAE,CAAC;gBAC1C,UAAU,GAAG,MAAM,mBAAmB,CAAC,EAAE,KAAK,EAAE,GAAG,CAAC,OAAO,CAAC,KAAK,EAAE,SAAS,EAAE,UAAU,EAAE,QAAQ,EAAE,IAAI,EAAE,EAAE,MAAM,CAAC,CAAC;YACtH,CAAC;QACH,CAAC;QAAC,MAAM,CAAC,CAAC,2BAA2B,CAAC,CAAC;QAEvC,MAAM,KAAK,GAAG;YACZ,kBAAkB,UAAU,EAAE;YAC9B,WAAW,MAAM,EAAE;YACnB,gBAAgB,OAAO,CAAC,eAAe,EAAE;YACzC,KAAK;YACL,cAAc;YACd,8BAA8B,KAAK,CAAC,OAAO,CAAC,MAAM,EAAE;YACpD,KAAK,CAAC,OAAO,CAAC,MAAM,GAAG,CAAC,CAAC,CAAC,CAAC,sBAAsB,KAAK,CAAC,OAAO,CAAC,IAAI,CAAC,IAAI,CAAC,EAAE,CAAC,CAAC,CAAC,kDAAkD;YAChI,KAAK,CAAC,OAAO,GAAG,CAAC,CAAC,CAAC,CAAC,+BAA+B,KAAK,CAAC,OAAO,EAAE,CAAC,CAAC,CAAC,IAAI;SAC1E,CAAC,MAAM,CAAC,OAAO,CAAC,CAAC;QAClB,MAAM,IAAI,GAAG,KAAK,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;QAC9B,OAAO,EAAE,OAAO,EAAE,CAAC,EAAE,IAAI,EAAE,MAAe,EAAE,IAAI,EAAE,UAAU,CAAC,CAAC,CAAC,GAAG,IAAI,OAAO,UAAU,EAAE,CAAC,CAAC,CAAC,IAAI,EAAE,CAAC,EAAE,CAAC;IACxG,CAAC,CACF,CAAC;IAEF,MAAM,CAAC,IAAI,CACT,SAAS,EACT,yHAAyH,EACzH;QACE,YAAY,EAAE,CAAC,CAAC,MAAM,EAAE,EAAE,QAAQ,EAAE,CAAC,CAAC,MAAM,EAAE;QAC9C,OAAO,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,QAAQ,CAAC,yEAAyE,CAAC;KACxG,EACD,KAAK,EAAE,EAAE,YAAY,EAAE,QAAQ,EAAE,OAAO,EAAE,EAAE,EAAE;QAC5C,MAAM,EAAE,EAAE,EAAE,GAAG,KAAK,EAAE,CAAC;QACvB,MAAM,KAAK,GAAG,IAAI,eAAe,CAAC,EAAE,CAAC,UAAU,CAAC,CAAC;QACjD,MAAM,MAAM,GAAG,KAAK,CAAC,OAAO,CAAC,YAAY,EAAE,QAAQ,EAAE,OAAO,CAAC,CAAC;QAC9D,OAAO,EAAE,OAAO,EAAE,CAAC,EAAE,IAAI,EAAE,MAAe,EAAE,IAAI,EAAE,mCAAmC,MAAM,CAAC,YAAY,YAAY,QAAQ,yBAAyB,MAAM,CAAC,iBAAiB,EAAE,EAAE,CAAC,EAAE,CAAC;IACvL,CAAC,CACF,CAAC;IAEF,MAAM,CAAC,IAAI,CACT,kBAAkB,EAClB,8GAA8G,EAC9G,EAAE,IAAI,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,QAAQ,EAAE,CAAC,QAAQ,CAAC,sBAAsB,CAAC,EAAE,EAChE,KAAK,EAAE,EAAE,IAAI,EAAE,EAAE,EAAE;QACjB,MAAM,EAAE,IAAI,EAAE,GAAG,KAAK,CAAC,IAAI,CAAC,CAAC;QAC7B,MAAM,MAAM,GAAG,MAAM,kBAAkB,CAAC,IAAI,CAAC,CAAC;QAC9C,OAAO,EAAE,OAAO,EAAE,CAAC,EAAE,IAAI,EAAE,MAAe,EAAE,IAAI,EAAE,MAAM,EAAE,CAAC,EAAE,CAAC;IAChE,CAAC,CACF,CAAC;IAEF,MAAM,CAAC,IAAI,CACT,mBAAmB,EACnB,yFAAyF,EACzF;QACE,KAAK,EAAE,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC,MAAM,EAAE,CAAC,CAAC,QAAQ,CAAC,4BAA4B,CAAC;QACjE,IAAI,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,QAAQ,EAAE;KAC5B,EACD,KAAK,EAAE,EAAE,KAAK,EAAE,IAAI,EAAE,EAAE,EAAE;QACxB,MAAM,EAAE,IAAI,EAAE,GAAG,KAAK,CAAC,IAAI,CAAC,CAAC;QAC7B,MAAM,MAAM,GAAG,MAAM,mBAAmB,CAAC,KAAK,EAAE,IAAI,CAAC,CAAC;QACtD,OAAO,EAAE,OAAO,EAAE,CAAC,EAAE,IAAI,EAAE,MAAe,EAAE,IAAI,EAAE,MAAM,EAAE,CAAC,EAAE,CAAC;IAChE,CAAC,CACF,CAAC;IAEF,MAAM,CAAC,IAAI,CACT,iBAAiB,EACjB,yFAAyF,EACzF,EAAE,IAAI,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,QAAQ,EAAE,EAAE,EAC/B,KAAK,EAAE,EAAE,IAAI,EAAE,EAAE,EAAE;QACjB,MAAM,EAAE,IAAI,EAAE,MAAM,EAAE,GAAG,KAAK,CAAC,IAAI,CAAC,CAAC;QACrC,MAAM,MAAM,GAAG,MAAM,mBAAmB,CAAC,IAAI,EAAE,MAAM,CAAC,CAAC;QACvD,OAAO,EAAE,OAAO,EAAE,CAAC,EAAE,IAAI,EAAE,MAAe,EAAE,IAAI,EAAE,MAAM,EAAE,CAAC,EAAE,CAAC;IAChE,CAAC,CACF,CAAC;IAEF,MAAM,CAAC,IAAI,CACT,kBAAkB,EAClB,wFAAwF,EACxF,EAAE,IAAI,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,QAAQ,EAAE,EAAE,EAC/B,KAAK,EAAE,EAAE,IAAI,EAAE,EAAE,EAAE;QACjB,MAAM,EAAE,IAAI,EAAE,GAAG,KAAK,CAAC,IAAI,CAAC,CAAC;QAC7B,MAAM,MAAM,GAAG,MAAM,oBAAoB,CAAC,IAAI,CAAC,CAAC;QAChD,OAAO,EAAE,OAAO,EAAE,CAAC,EAAE,IAAI,EAAE,MAAe,EAAE,IAAI,EAAE,MAAM,EAAE,CAAC,EAAE,CAAC;IAChE,CAAC,CACF,CAAC;AACJ,CAAC"}
|