skannr 0.1.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/.eslintrc.js +22 -0
- package/README.md +109 -0
- package/dist/agent-cli.d.ts +7 -0
- package/dist/agent-cli.d.ts.map +1 -0
- package/dist/agent-cli.js +364 -0
- package/dist/agent-cli.js.map +1 -0
- package/dist/agent.d.ts +115 -0
- package/dist/agent.d.ts.map +1 -0
- package/dist/agent.js +340 -0
- package/dist/agent.js.map +1 -0
- package/dist/benchmark.d.ts +53 -0
- package/dist/benchmark.d.ts.map +1 -0
- package/dist/benchmark.js +307 -0
- package/dist/benchmark.js.map +1 -0
- package/dist/cache.d.ts +97 -0
- package/dist/cache.d.ts.map +1 -0
- package/dist/cache.js +284 -0
- package/dist/cache.js.map +1 -0
- package/dist/cli.d.ts +6 -0
- package/dist/cli.d.ts.map +1 -0
- package/dist/cli.js +238 -0
- package/dist/cli.js.map +1 -0
- package/dist/config.d.ts +8 -0
- package/dist/config.d.ts.map +1 -0
- package/dist/config.js +52 -0
- package/dist/config.js.map +1 -0
- package/dist/index.d.ts +18 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +176 -0
- package/dist/index.js.map +1 -0
- package/dist/languages/GenericAdapter.d.ts +10 -0
- package/dist/languages/GenericAdapter.d.ts.map +1 -0
- package/dist/languages/GenericAdapter.js +41 -0
- package/dist/languages/GenericAdapter.js.map +1 -0
- package/dist/languages/LanguageAdapter.d.ts +14 -0
- package/dist/languages/LanguageAdapter.d.ts.map +1 -0
- package/dist/languages/LanguageAdapter.js +3 -0
- package/dist/languages/LanguageAdapter.js.map +1 -0
- package/dist/languages/PythonAdapter.d.ts +10 -0
- package/dist/languages/PythonAdapter.d.ts.map +1 -0
- package/dist/languages/PythonAdapter.js +98 -0
- package/dist/languages/PythonAdapter.js.map +1 -0
- package/dist/languages/TypeScriptAdapter.d.ts +17 -0
- package/dist/languages/TypeScriptAdapter.d.ts.map +1 -0
- package/dist/languages/TypeScriptAdapter.js +321 -0
- package/dist/languages/TypeScriptAdapter.js.map +1 -0
- package/dist/languages/registry.d.ts +4 -0
- package/dist/languages/registry.d.ts.map +1 -0
- package/dist/languages/registry.js +86 -0
- package/dist/languages/registry.js.map +1 -0
- package/dist/mapper.d.ts +49 -0
- package/dist/mapper.d.ts.map +1 -0
- package/dist/mapper.js +386 -0
- package/dist/mapper.js.map +1 -0
- package/dist/ranker-enhanced.d.ts +37 -0
- package/dist/ranker-enhanced.d.ts.map +1 -0
- package/dist/ranker-enhanced.js +395 -0
- package/dist/ranker-enhanced.js.map +1 -0
- package/dist/ranker.d.ts +14 -0
- package/dist/ranker.d.ts.map +1 -0
- package/dist/ranker.js +105 -0
- package/dist/ranker.js.map +1 -0
- package/dist/rocket-chat-scope.d.ts +7 -0
- package/dist/rocket-chat-scope.d.ts.map +1 -0
- package/dist/rocket-chat-scope.js +95 -0
- package/dist/rocket-chat-scope.js.map +1 -0
- package/dist/scanner.d.ts +16 -0
- package/dist/scanner.d.ts.map +1 -0
- package/dist/scanner.js +228 -0
- package/dist/scanner.js.map +1 -0
- package/dist/skeletonizer.d.ts +5 -0
- package/dist/skeletonizer.d.ts.map +1 -0
- package/dist/skeletonizer.js +52 -0
- package/dist/skeletonizer.js.map +1 -0
- package/dist/tokenizer.d.ts +9 -0
- package/dist/tokenizer.d.ts.map +1 -0
- package/dist/tokenizer.js +21 -0
- package/dist/tokenizer.js.map +1 -0
- package/dist/types.d.ts +68 -0
- package/dist/types.d.ts.map +1 -0
- package/dist/types.js +6 -0
- package/dist/types.js.map +1 -0
- package/gemini-extension/GEMINI.md +26 -0
- package/gemini-extension/gemini-extension.json +12 -0
- package/gemini-extension/package.json +14 -0
- package/gemini-extension/src/server.ts +63 -0
- package/gemini-extension/tsconfig.json +14 -0
- package/jest.config.js +5 -0
- package/package.json +46 -0
- package/src/agent-cli.ts +383 -0
- package/src/agent.ts +344 -0
- package/src/benchmark.ts +389 -0
- package/src/cache.ts +317 -0
- package/src/cli.ts +223 -0
- package/src/config.ts +22 -0
- package/src/index.ts +215 -0
- package/src/languages/GenericAdapter.ts +44 -0
- package/src/languages/LanguageAdapter.ts +14 -0
- package/src/languages/PythonAdapter.ts +74 -0
- package/src/languages/TypeScriptAdapter.ts +338 -0
- package/src/languages/registry.ts +49 -0
- package/src/mapper.ts +448 -0
- package/src/ranker-enhanced.ts +460 -0
- package/src/ranker.ts +92 -0
- package/src/scanner.ts +201 -0
- package/src/skeletonizer.ts +16 -0
- package/src/tokenizer.ts +20 -0
- package/src/types.ts +71 -0
- package/tests/agent.tools.test.ts +81 -0
- package/tests/benchmark.test.ts +31 -0
- package/tests/fixtures/sample.py +17 -0
- package/tests/fixtures/sample.ts +13 -0
- package/tests/fixtures/src/api/routes.ts +1 -0
- package/tests/fixtures/src/auth/permission.ts +3 -0
- package/tests/ranker-enhanced.test.ts +68 -0
- package/tests/ranker.test.ts +75 -0
- package/tests/scanner.scope.test.ts +41 -0
- package/tests/setup-fixtures.js +29 -0
- package/tests/skeletonizer.test.ts +142 -0
- package/tsconfig.json +21 -0
- package/uca-landing/index.html +17 -0
- package/uca-landing/package.json +23 -0
- package/uca-landing/postcss.config.js +6 -0
- package/uca-landing/src/App.jsx +43 -0
- package/uca-landing/src/components/AgentMode.jsx +45 -0
- package/uca-landing/src/components/CliReference.jsx +49 -0
- package/uca-landing/src/components/Features.jsx +63 -0
- package/uca-landing/src/components/Footer.jsx +35 -0
- package/uca-landing/src/components/Hero.jsx +124 -0
- package/uca-landing/src/components/HowItWorks.jsx +60 -0
- package/uca-landing/src/components/Install.jsx +90 -0
- package/uca-landing/src/components/LanguageSupport.jsx +63 -0
- package/uca-landing/src/components/Navbar.jsx +86 -0
- package/uca-landing/src/components/Problem.jsx +51 -0
- package/uca-landing/src/components/Reveal.jsx +40 -0
- package/uca-landing/src/components/WorksWith.jsx +59 -0
- package/uca-landing/src/hooks/useScrollNav.js +13 -0
- package/uca-landing/src/hooks/useTypewriter.js +41 -0
- package/uca-landing/src/index.css +13 -0
- package/uca-landing/src/main.jsx +10 -0
- package/uca-landing/tailwind.config.js +68 -0
- package/uca-landing/vite.config.js +6 -0
|
@@ -0,0 +1,142 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Tests for skeleton generation
|
|
3
|
+
*/
|
|
4
|
+
|
|
5
|
+
import * as fs from 'fs';
|
|
6
|
+
import * as path from 'path';
|
|
7
|
+
import * as os from 'os';
|
|
8
|
+
import { buildSkeletonForFile } from '../src/skeletonizer';
|
|
9
|
+
|
|
10
|
+
describe('buildSkeletonForFile', () => {
|
|
11
|
+
let tempDir: string;
|
|
12
|
+
let testFilePath: string;
|
|
13
|
+
|
|
14
|
+
beforeEach(() => {
|
|
15
|
+
// Create a temporary directory for test files
|
|
16
|
+
tempDir = fs.mkdtempSync(path.join(os.tmpdir(), 'skel-test-'));
|
|
17
|
+
testFilePath = path.join(tempDir, 'test.ts');
|
|
18
|
+
});
|
|
19
|
+
|
|
20
|
+
afterEach(() => {
|
|
21
|
+
// Clean up
|
|
22
|
+
if (fs.existsSync(tempDir)) {
|
|
23
|
+
fs.rmSync(tempDir, { recursive: true, force: true });
|
|
24
|
+
}
|
|
25
|
+
});
|
|
26
|
+
|
|
27
|
+
it('should generate skeleton for a simple class', () => {
|
|
28
|
+
const sourceCode = `
|
|
29
|
+
export class Calculator {
|
|
30
|
+
/**
|
|
31
|
+
* Adds two numbers
|
|
32
|
+
*/
|
|
33
|
+
add(a: number, b: number): number {
|
|
34
|
+
return a + b;
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
multiply(x: number, y: number): number {
|
|
38
|
+
const result = x * y;
|
|
39
|
+
return result;
|
|
40
|
+
}
|
|
41
|
+
}
|
|
42
|
+
`;
|
|
43
|
+
|
|
44
|
+
fs.writeFileSync(testFilePath, sourceCode);
|
|
45
|
+
const skeleton = buildSkeletonForFile(testFilePath);
|
|
46
|
+
|
|
47
|
+
// Should contain class declaration
|
|
48
|
+
expect(skeleton).toContain('export class Calculator');
|
|
49
|
+
|
|
50
|
+
// Should contain method signatures
|
|
51
|
+
expect(skeleton).toContain('add(a: number, b: number): number');
|
|
52
|
+
expect(skeleton).toContain('multiply(x: number, y: number): number');
|
|
53
|
+
|
|
54
|
+
// Should not contain implementation details
|
|
55
|
+
expect(skeleton).toContain('/* trimmed */');
|
|
56
|
+
expect(skeleton).not.toContain('return a + b');
|
|
57
|
+
expect(skeleton).not.toContain('const result = x * y');
|
|
58
|
+
});
|
|
59
|
+
|
|
60
|
+
it('should keep interface definitions intact', () => {
|
|
61
|
+
const sourceCode = `
|
|
62
|
+
export interface User {
|
|
63
|
+
id: string;
|
|
64
|
+
name: string;
|
|
65
|
+
email: string;
|
|
66
|
+
}
|
|
67
|
+
`;
|
|
68
|
+
|
|
69
|
+
fs.writeFileSync(testFilePath, sourceCode);
|
|
70
|
+
const skeleton = buildSkeletonForFile(testFilePath);
|
|
71
|
+
|
|
72
|
+
expect(skeleton).toContain('export interface User');
|
|
73
|
+
expect(skeleton).toContain('id: string');
|
|
74
|
+
expect(skeleton).toContain('name: string');
|
|
75
|
+
expect(skeleton).toContain('email: string');
|
|
76
|
+
});
|
|
77
|
+
|
|
78
|
+
it('should keep import statements', () => {
|
|
79
|
+
const sourceCode = `
|
|
80
|
+
import { Something } from './somewhere';
|
|
81
|
+
import * as fs from 'fs';
|
|
82
|
+
|
|
83
|
+
export function doWork(): void {
|
|
84
|
+
console.log('working');
|
|
85
|
+
}
|
|
86
|
+
`;
|
|
87
|
+
|
|
88
|
+
fs.writeFileSync(testFilePath, sourceCode);
|
|
89
|
+
const skeleton = buildSkeletonForFile(testFilePath);
|
|
90
|
+
|
|
91
|
+
expect(skeleton).toContain("import { Something } from './somewhere'");
|
|
92
|
+
expect(skeleton).toContain("import * as fs from 'fs'");
|
|
93
|
+
expect(skeleton).toContain('export function doWork(): void');
|
|
94
|
+
expect(skeleton).not.toContain("console.log('working')");
|
|
95
|
+
});
|
|
96
|
+
|
|
97
|
+
it('should handle type aliases', () => {
|
|
98
|
+
const sourceCode = `
|
|
99
|
+
export type Status = 'active' | 'inactive' | 'pending';
|
|
100
|
+
export type UserId = string;
|
|
101
|
+
`;
|
|
102
|
+
|
|
103
|
+
fs.writeFileSync(testFilePath, sourceCode);
|
|
104
|
+
const skeleton = buildSkeletonForFile(testFilePath);
|
|
105
|
+
|
|
106
|
+
expect(skeleton).toContain("export type Status = 'active' | 'inactive' | 'pending'");
|
|
107
|
+
expect(skeleton).toContain('export type UserId = string');
|
|
108
|
+
});
|
|
109
|
+
|
|
110
|
+
it('should handle functions with JSDoc', () => {
|
|
111
|
+
const sourceCode = `
|
|
112
|
+
/**
|
|
113
|
+
* Calculates the sum of an array
|
|
114
|
+
* @param numbers Array of numbers
|
|
115
|
+
* @returns The sum
|
|
116
|
+
*/
|
|
117
|
+
export function sum(numbers: number[]): number {
|
|
118
|
+
return numbers.reduce((a, b) => a + b, 0);
|
|
119
|
+
}
|
|
120
|
+
`;
|
|
121
|
+
|
|
122
|
+
fs.writeFileSync(testFilePath, sourceCode);
|
|
123
|
+
const skeleton = buildSkeletonForFile(testFilePath);
|
|
124
|
+
|
|
125
|
+
expect(skeleton).toContain('Calculates the sum');
|
|
126
|
+
expect(skeleton).toContain('export function sum(numbers: number[]): number');
|
|
127
|
+
expect(skeleton).toContain('/* trimmed */');
|
|
128
|
+
expect(skeleton).not.toContain('reduce');
|
|
129
|
+
});
|
|
130
|
+
|
|
131
|
+
it('should handle malformed TypeScript gracefully', () => {
|
|
132
|
+
const sourceCode = 'export const x = {{{';
|
|
133
|
+
|
|
134
|
+
fs.writeFileSync(testFilePath, sourceCode);
|
|
135
|
+
const skeleton = buildSkeletonForFile(testFilePath);
|
|
136
|
+
|
|
137
|
+
// ts-morph is robust and may still parse partial content
|
|
138
|
+
// Just verify it returns some output without crashing
|
|
139
|
+
expect(skeleton).toBeDefined();
|
|
140
|
+
expect(skeleton.length).toBeGreaterThan(0);
|
|
141
|
+
});
|
|
142
|
+
});
|
package/tsconfig.json
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
{
|
|
2
|
+
"compilerOptions": {
|
|
3
|
+
"target": "ES2022",
|
|
4
|
+
"module": "commonjs",
|
|
5
|
+
"lib": ["ES2022"],
|
|
6
|
+
"outDir": "./dist",
|
|
7
|
+
"rootDir": "./src",
|
|
8
|
+
"declaration": true,
|
|
9
|
+
"declarationMap": true,
|
|
10
|
+
"sourceMap": true,
|
|
11
|
+
"strict": true,
|
|
12
|
+
"esModuleInterop": true,
|
|
13
|
+
"skipLibCheck": true,
|
|
14
|
+
"forceConsistentCasingInFileNames": true,
|
|
15
|
+
"moduleResolution": "node",
|
|
16
|
+
"resolveJsonModule": true,
|
|
17
|
+
"types": ["node", "jest"]
|
|
18
|
+
},
|
|
19
|
+
"include": ["src/**/*"],
|
|
20
|
+
"exclude": ["node_modules", "dist", "tests"]
|
|
21
|
+
}
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
<!doctype html>
|
|
2
|
+
<html lang="en">
|
|
3
|
+
<head>
|
|
4
|
+
<meta charset="UTF-8" />
|
|
5
|
+
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
|
|
6
|
+
<title>Universal Code Analyzer</title>
|
|
7
|
+
<link rel="preconnect" href="https://fonts.googleapis.com" />
|
|
8
|
+
<link
|
|
9
|
+
href="https://fonts.googleapis.com/css2?family=Inter:wght@400;500;600;700&family=JetBrains+Mono:wght@400;500&display=swap"
|
|
10
|
+
rel="stylesheet"
|
|
11
|
+
/>
|
|
12
|
+
</head>
|
|
13
|
+
<body>
|
|
14
|
+
<div id="root"></div>
|
|
15
|
+
<script type="module" src="/src/main.jsx"></script>
|
|
16
|
+
</body>
|
|
17
|
+
</html>
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "uca-landing",
|
|
3
|
+
"private": true,
|
|
4
|
+
"version": "0.0.0",
|
|
5
|
+
"type": "module",
|
|
6
|
+
"scripts": {
|
|
7
|
+
"dev": "vite",
|
|
8
|
+
"build": "vite build",
|
|
9
|
+
"preview": "vite preview"
|
|
10
|
+
},
|
|
11
|
+
"dependencies": {
|
|
12
|
+
"lucide-react": "^0.525.0",
|
|
13
|
+
"react": "^18.3.1",
|
|
14
|
+
"react-dom": "^18.3.1"
|
|
15
|
+
},
|
|
16
|
+
"devDependencies": {
|
|
17
|
+
"@vitejs/plugin-react": "^4.3.1",
|
|
18
|
+
"autoprefixer": "^10.4.21",
|
|
19
|
+
"postcss": "^8.5.6",
|
|
20
|
+
"tailwindcss": "^3.4.17",
|
|
21
|
+
"vite": "^5.4.10"
|
|
22
|
+
}
|
|
23
|
+
}
|
|
@@ -0,0 +1,43 @@
|
|
|
1
|
+
import Navbar from './components/Navbar'
|
|
2
|
+
import Hero from './components/Hero'
|
|
3
|
+
import Problem from './components/Problem'
|
|
4
|
+
import HowItWorks from './components/HowItWorks'
|
|
5
|
+
import Features from './components/Features'
|
|
6
|
+
import LanguageSupport from './components/LanguageSupport'
|
|
7
|
+
import Install from './components/Install'
|
|
8
|
+
import CliReference from './components/CliReference'
|
|
9
|
+
import WorksWith from './components/WorksWith'
|
|
10
|
+
import AgentMode from './components/AgentMode'
|
|
11
|
+
import Footer from './components/Footer'
|
|
12
|
+
|
|
13
|
+
export default function App() {
|
|
14
|
+
return (
|
|
15
|
+
<div className="relative min-h-screen overflow-x-hidden bg-bg text-white font-sans">
|
|
16
|
+
<div
|
|
17
|
+
className="pointer-events-none fixed inset-0 -z-10"
|
|
18
|
+
aria-hidden
|
|
19
|
+
>
|
|
20
|
+
<div
|
|
21
|
+
className="absolute -left-[20%] top-[10%] h-[520px] w-[520px] rounded-full bg-accent/[0.07] blur-[120px] motion-safe:animate-drift"
|
|
22
|
+
/>
|
|
23
|
+
<div
|
|
24
|
+
className="absolute -right-[15%] top-[40%] h-[420px] w-[420px] rounded-full bg-purple/[0.08] blur-[100px] motion-safe:animate-drift motion-safe:[animation-delay:-7s] motion-safe:[animation-duration:28s]"
|
|
25
|
+
/>
|
|
26
|
+
<div
|
|
27
|
+
className="absolute bottom-0 left-1/3 h-[380px] w-[380px] rounded-full bg-green/[0.05] blur-[90px] motion-safe:animate-drift motion-safe:[animation-delay:-12s] motion-safe:[animation-duration:26s]"
|
|
28
|
+
/>
|
|
29
|
+
</div>
|
|
30
|
+
<Navbar />
|
|
31
|
+
<Hero />
|
|
32
|
+
<Problem />
|
|
33
|
+
<HowItWorks />
|
|
34
|
+
<Features />
|
|
35
|
+
<LanguageSupport />
|
|
36
|
+
<Install />
|
|
37
|
+
<CliReference />
|
|
38
|
+
<WorksWith />
|
|
39
|
+
<AgentMode />
|
|
40
|
+
<Footer />
|
|
41
|
+
</div>
|
|
42
|
+
)
|
|
43
|
+
}
|
|
@@ -0,0 +1,45 @@
|
|
|
1
|
+
import Reveal from './Reveal'
|
|
2
|
+
|
|
3
|
+
export default function AgentMode() {
|
|
4
|
+
return (
|
|
5
|
+
<section className="py-24 px-5">
|
|
6
|
+
<div className="max-w-5xl mx-auto">
|
|
7
|
+
<Reveal>
|
|
8
|
+
<h2 className="text-3xl md:text-5xl font-bold text-center tracking-tight">
|
|
9
|
+
Agent mode. For when you need to explore.
|
|
10
|
+
</h2>
|
|
11
|
+
</Reveal>
|
|
12
|
+
|
|
13
|
+
<Reveal delay={100} className="mt-12 block">
|
|
14
|
+
<div className="overflow-hidden rounded-xl border border-border bg-card transition-all duration-300 hover:border-white/10 hover:shadow-[0_0_40px_-12px_rgba(0,212,255,0.12)]">
|
|
15
|
+
<div className="flex items-center gap-2 border-b border-white/5 px-4 py-3">
|
|
16
|
+
<span className="h-3 w-3 rounded-full bg-[#ff5f57]" />
|
|
17
|
+
<span className="h-3 w-3 rounded-full bg-[#febc2e]" />
|
|
18
|
+
<span className="h-3 w-3 rounded-full bg-[#28c840]" />
|
|
19
|
+
<span className="ml-2 font-mono text-xs text-[#888]">bash</span>
|
|
20
|
+
</div>
|
|
21
|
+
<pre className="overflow-x-auto p-5 font-mono text-sm leading-7 text-[#e8e8e8]">
|
|
22
|
+
<span>$ uca-agent --root ./my-project</span>
|
|
23
|
+
{'\n\n'}
|
|
24
|
+
<span className="text-accent">{'>'}</span> <span>/help</span>
|
|
25
|
+
{'\n'} <span className="text-white">/files</span> List currently retrieved files
|
|
26
|
+
{'\n'} <span className="text-white">/symbols <query></span> Search for symbols in the codebase
|
|
27
|
+
{'\n'} <span className="text-white">/symbol <id></span> Get full implementation of a symbol
|
|
28
|
+
{'\n'} <span className="text-white">/deps <filePath></span> Show imports and exports for a file
|
|
29
|
+
{'\n'} <span className="text-white">/refresh</span> Re-analyze project with new context
|
|
30
|
+
{'\n'} <span className="text-white">/stats</span> Show cache and mapping statistics
|
|
31
|
+
{'\n'} <span className="text-white">/exit</span> Quit
|
|
32
|
+
{'\n\n'}
|
|
33
|
+
<span className="text-accent">{'>'}</span> <span>/symbols auth</span>
|
|
34
|
+
{'\n'} Found 4 symbols:
|
|
35
|
+
{'\n'} <span className="text-accent">→</span> AuthManager (class) <span className="text-[#888]">src/auth/AuthManager.ts:12</span>
|
|
36
|
+
{'\n'} <span className="text-accent">→</span> validateToken (fn) <span className="text-[#888]">src/auth/AuthManager.ts:24</span>
|
|
37
|
+
{'\n'} <span className="text-accent">→</span> AuthMiddleware (class) <span className="text-[#888]">src/middleware/auth.ts:8</span>
|
|
38
|
+
{'\n'} <span className="text-accent">→</span> authRouter (const) <span className="text-[#888]">src/routes/auth.ts:3</span>
|
|
39
|
+
</pre>
|
|
40
|
+
</div>
|
|
41
|
+
</Reveal>
|
|
42
|
+
</div>
|
|
43
|
+
</section>
|
|
44
|
+
)
|
|
45
|
+
}
|
|
@@ -0,0 +1,49 @@
|
|
|
1
|
+
import Reveal from './Reveal'
|
|
2
|
+
|
|
3
|
+
const flags = [
|
|
4
|
+
['--question', 'The question to answer (required)'],
|
|
5
|
+
['--root', 'Path to repo (default: current directory)'],
|
|
6
|
+
['--limit', 'Number of files to return (default: 10)'],
|
|
7
|
+
['--modules', 'Comma-separated module names to focus on'],
|
|
8
|
+
['--lang', 'Force language: typescript, python, auto'],
|
|
9
|
+
['--with-mapping', 'Generate symbol-to-file mapping'],
|
|
10
|
+
['--skip-cache', 'Bypass cache for this query'],
|
|
11
|
+
['--cache-stats', 'Show cache statistics'],
|
|
12
|
+
['--cache-clear', 'Clear the cache'],
|
|
13
|
+
['--interactive', 'Start interactive agent mode'],
|
|
14
|
+
]
|
|
15
|
+
|
|
16
|
+
export default function CliReference() {
|
|
17
|
+
return (
|
|
18
|
+
<section className="py-24 px-5">
|
|
19
|
+
<div className="max-w-5xl mx-auto">
|
|
20
|
+
<Reveal>
|
|
21
|
+
<h2 className="text-3xl md:text-5xl font-bold text-center tracking-tight">All CLI options.</h2>
|
|
22
|
+
</Reveal>
|
|
23
|
+
<Reveal delay={80}>
|
|
24
|
+
<div className="mt-12 overflow-hidden rounded-xl border border-border bg-card transition-colors duration-300 hover:border-white/10">
|
|
25
|
+
<table className="w-full text-left">
|
|
26
|
+
<thead className="border-b border-white/5">
|
|
27
|
+
<tr className="text-[#888] text-sm">
|
|
28
|
+
<th className="px-6 py-4 font-medium">Flag</th>
|
|
29
|
+
<th className="px-6 py-4 font-medium">Description</th>
|
|
30
|
+
</tr>
|
|
31
|
+
</thead>
|
|
32
|
+
<tbody>
|
|
33
|
+
{flags.map(([flag, description]) => (
|
|
34
|
+
<tr
|
|
35
|
+
key={flag}
|
|
36
|
+
className="border-b border-white/5 transition-colors duration-200 last:border-b-0 hover:bg-white/[0.03]"
|
|
37
|
+
>
|
|
38
|
+
<td className="px-6 py-4 font-mono text-accent">{flag}</td>
|
|
39
|
+
<td className="px-6 py-4 text-[#d0d0d0]">{description}</td>
|
|
40
|
+
</tr>
|
|
41
|
+
))}
|
|
42
|
+
</tbody>
|
|
43
|
+
</table>
|
|
44
|
+
</div>
|
|
45
|
+
</Reveal>
|
|
46
|
+
</div>
|
|
47
|
+
</section>
|
|
48
|
+
)
|
|
49
|
+
}
|
|
@@ -0,0 +1,63 @@
|
|
|
1
|
+
import { Code2, Database, FileSearch, Network, Plug, Zap } from 'lucide-react'
|
|
2
|
+
import Reveal from './Reveal'
|
|
3
|
+
|
|
4
|
+
const features = [
|
|
5
|
+
{
|
|
6
|
+
icon: Network,
|
|
7
|
+
title: 'Hybrid Retrieval',
|
|
8
|
+
body: 'Lexical + structural + dependency-graph ranking. Finds architecturally central files, not just keyword matches.',
|
|
9
|
+
},
|
|
10
|
+
{
|
|
11
|
+
icon: Zap,
|
|
12
|
+
title: '96.5% Token Reduction',
|
|
13
|
+
body: 'Skeleton generation strips bodies while preserving signatures and types. Feed entire codebases to your AI without hitting limits.',
|
|
14
|
+
},
|
|
15
|
+
{
|
|
16
|
+
icon: Code2,
|
|
17
|
+
title: 'Auto Language Detection',
|
|
18
|
+
body: "Detects the repo's dominant language automatically. TypeScript, JavaScript, and Python supported. Generic fallback for everything else.",
|
|
19
|
+
},
|
|
20
|
+
{
|
|
21
|
+
icon: Database,
|
|
22
|
+
title: 'Smart Caching',
|
|
23
|
+
body: 'MD5-based file hashing detects changes automatically. Repeated queries run in milliseconds. 24-hour TTL with manual controls.',
|
|
24
|
+
},
|
|
25
|
+
{
|
|
26
|
+
icon: FileSearch,
|
|
27
|
+
title: 'Grounded Citations',
|
|
28
|
+
body: 'Every response includes an Evidence section listing the exact files and symbols used. Verify AI answers by tracing to source.',
|
|
29
|
+
},
|
|
30
|
+
{
|
|
31
|
+
icon: Plug,
|
|
32
|
+
title: 'MCP Server Built In',
|
|
33
|
+
body: 'Runs as a Model Context Protocol server. Plug into Gemini CLI, Claude Code, Cursor, or any MCP-compatible tool.',
|
|
34
|
+
},
|
|
35
|
+
]
|
|
36
|
+
|
|
37
|
+
export default function Features() {
|
|
38
|
+
return (
|
|
39
|
+
<section id="features" className="py-24 px-5">
|
|
40
|
+
<div className="max-w-6xl mx-auto">
|
|
41
|
+
<Reveal>
|
|
42
|
+
<h2 className="text-3xl md:text-5xl font-bold text-center tracking-tight">
|
|
43
|
+
Everything you need. Nothing you don't.
|
|
44
|
+
</h2>
|
|
45
|
+
</Reveal>
|
|
46
|
+
<div className="mt-14 grid grid-cols-1 md:grid-cols-2 lg:grid-cols-3 gap-5">
|
|
47
|
+
{features.map(({ icon: Icon, title, body }, i) => (
|
|
48
|
+
<Reveal key={title} delay={i * 70} className="h-full">
|
|
49
|
+
<article className="group h-full rounded-xl border border-border bg-card p-6 transition-all duration-300 hover:-translate-y-1 hover:border-accent/40 hover:bg-card-hover hover:shadow-[0_0_36px_rgba(0,212,255,0.12)]">
|
|
50
|
+
<Icon
|
|
51
|
+
size={24}
|
|
52
|
+
className="mb-4 text-accent transition-transform duration-300 group-hover:scale-110 group-hover:rotate-3"
|
|
53
|
+
/>
|
|
54
|
+
<h3 className="mb-2 text-xl font-semibold">{title}</h3>
|
|
55
|
+
<p className="text-[#888]">{body}</p>
|
|
56
|
+
</article>
|
|
57
|
+
</Reveal>
|
|
58
|
+
))}
|
|
59
|
+
</div>
|
|
60
|
+
</div>
|
|
61
|
+
</section>
|
|
62
|
+
)
|
|
63
|
+
}
|
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
import Reveal from './Reveal'
|
|
2
|
+
|
|
3
|
+
export default function Footer() {
|
|
4
|
+
return (
|
|
5
|
+
<footer className="border-t border-white/5 py-12 px-5">
|
|
6
|
+
<Reveal>
|
|
7
|
+
<div className="mx-auto grid max-w-6xl grid-cols-1 items-center gap-8 md:grid-cols-3">
|
|
8
|
+
<div>
|
|
9
|
+
<p className="font-mono text-lg">Skannr</p>
|
|
10
|
+
<p className="mt-1 text-[#888]">Open-source · MIT License</p>
|
|
11
|
+
</div>
|
|
12
|
+
|
|
13
|
+
<p className="text-[#888] md:text-center">
|
|
14
|
+
Built by Vignesh <span className="text-accent">♥</span>
|
|
15
|
+
</p>
|
|
16
|
+
|
|
17
|
+
<div className="flex gap-5 md:justify-self-end">
|
|
18
|
+
<a
|
|
19
|
+
href="https://github.com/7vignesh/code-analyzer"
|
|
20
|
+
className="text-[#888] transition-colors hover:text-accent"
|
|
21
|
+
>
|
|
22
|
+
GitHub
|
|
23
|
+
</a>
|
|
24
|
+
<a
|
|
25
|
+
href="https://npmjs.com/package/skannr"
|
|
26
|
+
className="text-[#888] transition-colors hover:text-accent"
|
|
27
|
+
>
|
|
28
|
+
npm
|
|
29
|
+
</a>
|
|
30
|
+
</div>
|
|
31
|
+
</div>
|
|
32
|
+
</Reveal>
|
|
33
|
+
</footer>
|
|
34
|
+
)
|
|
35
|
+
}
|
|
@@ -0,0 +1,124 @@
|
|
|
1
|
+
import { useEffect, useMemo, useState } from 'react'
|
|
2
|
+
import { useTypewriter } from '../hooks/useTypewriter'
|
|
3
|
+
|
|
4
|
+
function renderLine(line, showCursor) {
|
|
5
|
+
const baseClass = line.startsWith('✓')
|
|
6
|
+
? 'text-green'
|
|
7
|
+
: line.startsWith('───') || line.startsWith('────────────────')
|
|
8
|
+
? 'text-[#333]'
|
|
9
|
+
: line.startsWith('Evidence:')
|
|
10
|
+
? 'text-accent'
|
|
11
|
+
: 'text-[#e8e8e8]'
|
|
12
|
+
|
|
13
|
+
const parts = line.split('{ ... }')
|
|
14
|
+
|
|
15
|
+
return (
|
|
16
|
+
<span className={baseClass}>
|
|
17
|
+
{parts.map((part, idx) => (
|
|
18
|
+
<span key={`${part}-${idx}`}>
|
|
19
|
+
{part}
|
|
20
|
+
{idx < parts.length - 1 && <span className="text-[#777]">{'{ ... }'}</span>}
|
|
21
|
+
</span>
|
|
22
|
+
))}
|
|
23
|
+
{showCursor && <span className="animate-pulse text-white">|</span>}
|
|
24
|
+
</span>
|
|
25
|
+
)
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
export default function Hero() {
|
|
29
|
+
const [start, setStart] = useState(false)
|
|
30
|
+
|
|
31
|
+
const lines = useMemo(
|
|
32
|
+
() => [
|
|
33
|
+
'$ uca --question "how does authentication work?" --root ./my-project',
|
|
34
|
+
'',
|
|
35
|
+
'✓ Detected language: TypeScript',
|
|
36
|
+
'✓ Discovered modules: auth, api, middleware, db',
|
|
37
|
+
'✓ Scanning 1,847 files...',
|
|
38
|
+
'',
|
|
39
|
+
' Ranked 8 relevant files in 1.1s',
|
|
40
|
+
' Token reduction: 96.5% vs full scan',
|
|
41
|
+
'',
|
|
42
|
+
'─── src/auth/AuthManager.ts ──────────────────',
|
|
43
|
+
' export class AuthManager {',
|
|
44
|
+
' constructor(private db: Database) {}',
|
|
45
|
+
' async validateToken(token: string): Promise<User | null> { ... }',
|
|
46
|
+
' async createSession(userId: string): Promise<Session> { ... }',
|
|
47
|
+
' }',
|
|
48
|
+
'──────────────────────────────────────────────',
|
|
49
|
+
'',
|
|
50
|
+
'Evidence: AuthManager.ts · SessionStore.ts · middleware/auth.ts',
|
|
51
|
+
],
|
|
52
|
+
[]
|
|
53
|
+
)
|
|
54
|
+
|
|
55
|
+
useEffect(() => {
|
|
56
|
+
const t = setTimeout(() => setStart(true), 800)
|
|
57
|
+
return () => clearTimeout(t)
|
|
58
|
+
}, [])
|
|
59
|
+
|
|
60
|
+
const { displayed, done } = useTypewriter(start ? lines : [], 30, 400)
|
|
61
|
+
|
|
62
|
+
return (
|
|
63
|
+
<section
|
|
64
|
+
className="relative px-5 pt-32 pb-24 min-h-screen flex flex-col items-center justify-center"
|
|
65
|
+
style={{
|
|
66
|
+
backgroundImage: 'radial-gradient(rgba(255,255,255,0.04) 1px, transparent 1px)',
|
|
67
|
+
backgroundSize: '32px 32px',
|
|
68
|
+
}}
|
|
69
|
+
>
|
|
70
|
+
<div
|
|
71
|
+
className="inline-flex items-center gap-2 border border-white/10 rounded-full px-4 py-1 text-sm text-gray-400 mb-8 opacity-0 motion-safe:animate-fade-in-up motion-reduce:opacity-100 motion-reduce:translate-y-0 [animation-delay:0ms]"
|
|
72
|
+
>
|
|
73
|
+
<span className="w-2 h-2 rounded-full bg-green motion-safe:animate-pulse" />
|
|
74
|
+
CLI + MCP Server · Open Source
|
|
75
|
+
</div>
|
|
76
|
+
|
|
77
|
+
<h1 className="text-4xl md:text-6xl font-bold tracking-tight text-center leading-tight opacity-0 motion-safe:animate-fade-in-up motion-reduce:opacity-100 motion-reduce:translate-y-0 [animation-delay:80ms]">
|
|
78
|
+
Any repo. Any question.
|
|
79
|
+
<br />
|
|
80
|
+
<span className="text-accent">Instantly understood.</span>
|
|
81
|
+
</h1>
|
|
82
|
+
|
|
83
|
+
<p className="mt-6 max-w-xl text-center text-lg text-[#888] opacity-0 motion-safe:animate-fade-in-up motion-reduce:opacity-100 motion-reduce:translate-y-0 [animation-delay:180ms]">
|
|
84
|
+
Universal Code Analyzer helps AI assistants understand entire codebases using structural
|
|
85
|
+
skeletons and hybrid ranking, so you can ask architectural questions without context limits.
|
|
86
|
+
</p>
|
|
87
|
+
|
|
88
|
+
<div className="flex flex-col sm:flex-row gap-4 mt-10 opacity-0 motion-safe:animate-fade-in-up motion-reduce:opacity-100 motion-reduce:translate-y-0 [animation-delay:280ms]">
|
|
89
|
+
<a
|
|
90
|
+
href="#install"
|
|
91
|
+
className="bg-accent text-black font-semibold px-6 py-3 rounded-lg shadow-[0_0_24px_-4px_rgba(0,212,255,0.5)] transition-all duration-300 hover:opacity-95 hover:shadow-[0_0_32px_-2px_rgba(0,212,255,0.65)] hover:-translate-y-0.5 active:translate-y-0"
|
|
92
|
+
>
|
|
93
|
+
Get started
|
|
94
|
+
</a>
|
|
95
|
+
<a
|
|
96
|
+
href="https://github.com/7vignesh/code-analyzer"
|
|
97
|
+
className="border border-white/20 px-6 py-3 rounded-lg transition-all duration-300 hover:border-accent/60 hover:text-accent hover:-translate-y-0.5 active:translate-y-0"
|
|
98
|
+
>
|
|
99
|
+
View on GitHub
|
|
100
|
+
</a>
|
|
101
|
+
</div>
|
|
102
|
+
|
|
103
|
+
<div className="w-full max-w-3xl mx-auto mt-16 rounded-xl border border-border bg-card overflow-hidden opacity-0 shadow-[0_0_40px_-16px_rgba(0,212,255,0.12)] motion-safe:animate-scale-in motion-safe:[animation-delay:420ms] motion-reduce:opacity-100 motion-reduce:translate-y-0 transition-[box-shadow,border-color] duration-500 hover:border-accent/25 hover:shadow-[0_0_48px_-12px_rgba(0,212,255,0.2)]">
|
|
104
|
+
<div className="flex items-center gap-2 px-4 py-3 border-b border-white/5">
|
|
105
|
+
<span className="w-3 h-3 rounded-full bg-[#ff5f57]" />
|
|
106
|
+
<span className="w-3 h-3 rounded-full bg-[#febc2e]" />
|
|
107
|
+
<span className="w-3 h-3 rounded-full bg-[#28c840]" />
|
|
108
|
+
<span className="ml-2 text-xs font-mono text-[#888]">bash</span>
|
|
109
|
+
</div>
|
|
110
|
+
<pre className="p-5 overflow-x-auto font-mono text-sm leading-7">
|
|
111
|
+
{lines.map((_, idx) => {
|
|
112
|
+
const current = displayed[idx] ?? ''
|
|
113
|
+
const showCursor = !done && idx === displayed.length - 1
|
|
114
|
+
return (
|
|
115
|
+
<div key={`line-${idx}`} className="min-h-6">
|
|
116
|
+
{renderLine(current, showCursor)}
|
|
117
|
+
</div>
|
|
118
|
+
)
|
|
119
|
+
})}
|
|
120
|
+
</pre>
|
|
121
|
+
</div>
|
|
122
|
+
</section>
|
|
123
|
+
)
|
|
124
|
+
}
|
|
@@ -0,0 +1,60 @@
|
|
|
1
|
+
import Reveal from './Reveal'
|
|
2
|
+
|
|
3
|
+
const steps = [
|
|
4
|
+
{
|
|
5
|
+
title: 'Point it at any repo',
|
|
6
|
+
code: 'uca --question "..." --root /path/to/any/project',
|
|
7
|
+
desc: "No configuration needed. Works on repos you've never touched before. Auto-detects language and module structure from the folder layout.",
|
|
8
|
+
},
|
|
9
|
+
{
|
|
10
|
+
title: 'Modules discovered automatically',
|
|
11
|
+
desc: 'Reads the folder structure and identifies logical modules - src/auth, src/api, lib/db. No config file required, though one is supported for fine-tuned control.',
|
|
12
|
+
},
|
|
13
|
+
{
|
|
14
|
+
title: 'Hybrid ranking finds the right files',
|
|
15
|
+
desc: 'Three signals combined: lexical match (keyword relevance), structural analysis (export/import density), and dependency graph centrality. Finds architecturally important files - not just keyword matches.',
|
|
16
|
+
},
|
|
17
|
+
{
|
|
18
|
+
title: 'Skeletons compress without losing meaning',
|
|
19
|
+
desc: 'Function bodies stripped. Signatures, types, interfaces, and imports remain. The AI gets the full architectural picture at 3% of the token cost. Citations tell you exactly which files were used.',
|
|
20
|
+
},
|
|
21
|
+
]
|
|
22
|
+
|
|
23
|
+
export default function HowItWorks() {
|
|
24
|
+
return (
|
|
25
|
+
<section id="how-it-works" className="py-24 px-5">
|
|
26
|
+
<div className="max-w-5xl mx-auto">
|
|
27
|
+
<Reveal>
|
|
28
|
+
<h2 className="text-3xl md:text-5xl font-bold text-center tracking-tight">
|
|
29
|
+
Simple to use. Sophisticated underneath.
|
|
30
|
+
</h2>
|
|
31
|
+
</Reveal>
|
|
32
|
+
|
|
33
|
+
<div className="mt-14 overflow-hidden rounded-xl border border-border bg-card px-5 md:px-10">
|
|
34
|
+
{steps.map((step, idx) => (
|
|
35
|
+
<Reveal key={step.title} delay={idx * 100} className="w-full">
|
|
36
|
+
<div
|
|
37
|
+
className={`group grid gap-6 py-10 md:grid-cols-[120px,1fr] ${idx < steps.length - 1 ? 'border-b border-white/5' : ''}`}
|
|
38
|
+
>
|
|
39
|
+
<span className="font-mono text-7xl font-bold leading-none text-white/5 transition-colors duration-500 group-hover:text-accent/25">
|
|
40
|
+
{String(idx + 1).padStart(2, '0')}
|
|
41
|
+
</span>
|
|
42
|
+
<div>
|
|
43
|
+
<h3 className="text-2xl font-semibold transition-colors duration-300 group-hover:text-white">
|
|
44
|
+
{step.title}
|
|
45
|
+
</h3>
|
|
46
|
+
{step.code && (
|
|
47
|
+
<code className="mt-4 block w-fit rounded-lg border border-border px-3 py-2 font-mono text-sm text-accent transition-all duration-300 group-hover:border-accent/30 group-hover:shadow-[0_0_20px_-8px_rgba(0,212,255,0.35)]">
|
|
48
|
+
{step.code}
|
|
49
|
+
</code>
|
|
50
|
+
)}
|
|
51
|
+
<p className="mt-4 text-[#888]">{step.desc}</p>
|
|
52
|
+
</div>
|
|
53
|
+
</div>
|
|
54
|
+
</Reveal>
|
|
55
|
+
))}
|
|
56
|
+
</div>
|
|
57
|
+
</div>
|
|
58
|
+
</section>
|
|
59
|
+
)
|
|
60
|
+
}
|