skannr 0.1.6 → 0.2.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 (58) hide show
  1. package/dist/languages/TreeSitterAdapter.d.ts +30 -0
  2. package/dist/languages/TreeSitterAdapter.d.ts.map +1 -0
  3. package/dist/languages/TreeSitterAdapter.js +466 -0
  4. package/dist/languages/TreeSitterAdapter.js.map +1 -0
  5. package/dist/languages/grammars/tree-sitter-go.wasm +0 -0
  6. package/dist/languages/grammars/tree-sitter-java.wasm +0 -0
  7. package/dist/languages/grammars/tree-sitter-python.wasm +0 -0
  8. package/dist/languages/grammars/tree-sitter-rust.wasm +0 -0
  9. package/dist/languages/lang-config.d.ts +38 -0
  10. package/dist/languages/lang-config.d.ts.map +1 -0
  11. package/dist/languages/lang-config.js +85 -0
  12. package/dist/languages/lang-config.js.map +1 -0
  13. package/dist/languages/registry.d.ts +6 -0
  14. package/dist/languages/registry.d.ts.map +1 -1
  15. package/dist/languages/registry.js +18 -4
  16. package/dist/languages/registry.js.map +1 -1
  17. package/package.json +4 -7
  18. package/src/languages/TreeSitterAdapter.ts +431 -0
  19. package/src/languages/lang-config.ts +113 -0
  20. package/src/languages/registry.ts +65 -49
  21. package/src/languages/PythonAdapter.ts +0 -302
  22. package/tests/agent.tools.test.ts +0 -81
  23. package/tests/benchmark.test.ts +0 -31
  24. package/tests/blast-radius.test.ts +0 -290
  25. package/tests/fixtures/sample.py +0 -17
  26. package/tests/fixtures/sample.ts +0 -13
  27. package/tests/fixtures/src/api/routes.ts +0 -1
  28. package/tests/fixtures/src/auth/permission.ts +0 -3
  29. package/tests/python-adapter.test.ts +0 -31
  30. package/tests/ranker-enhanced.test.ts +0 -70
  31. package/tests/ranker.test.ts +0 -79
  32. package/tests/scanner.scope.test.ts +0 -67
  33. package/tests/setup-fixtures.js +0 -29
  34. package/tests/skeletonizer.test.ts +0 -149
  35. package/uca-landing/index.html +0 -17
  36. package/uca-landing/package.json +0 -23
  37. package/uca-landing/postcss.config.js +0 -6
  38. package/uca-landing/src/App.jsx +0 -45
  39. package/uca-landing/src/components/AgentMode.jsx +0 -45
  40. package/uca-landing/src/components/CliReference.jsx +0 -89
  41. package/uca-landing/src/components/Features.jsx +0 -88
  42. package/uca-landing/src/components/Footer.jsx +0 -35
  43. package/uca-landing/src/components/Hero.jsx +0 -125
  44. package/uca-landing/src/components/HowItWorks.jsx +0 -65
  45. package/uca-landing/src/components/Install.jsx +0 -103
  46. package/uca-landing/src/components/LanguageSupport.jsx +0 -63
  47. package/uca-landing/src/components/Navbar.jsx +0 -86
  48. package/uca-landing/src/components/Problem.jsx +0 -51
  49. package/uca-landing/src/components/Reveal.jsx +0 -40
  50. package/uca-landing/src/components/TokenSavings.jsx +0 -126
  51. package/uca-landing/src/components/WorksWith.jsx +0 -59
  52. package/uca-landing/src/hooks/useScrollNav.js +0 -13
  53. package/uca-landing/src/hooks/useTypewriter.js +0 -41
  54. package/uca-landing/src/index.css +0 -13
  55. package/uca-landing/src/main.jsx +0 -10
  56. package/uca-landing/tailwind.config.js +0 -68
  57. package/uca-landing/vercel.json +0 -4
  58. package/uca-landing/vite.config.js +0 -6
@@ -1,149 +0,0 @@
1
- /**
2
- * Tests for skeleton generation
3
- */
4
-
5
- import * as fs from 'fs';
6
- import * as os from 'os';
7
- import * as path from 'path';
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, lineRanges } = buildSkeletonForFile(testFilePath, tempDir);
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
- expect(skeleton).toMatch(/\/\/ test\.ts:\d+/);
60
- expect(lineRanges?.some((r) => r.symbol === 'class Calculator')).toBe(true);
61
- expect(lineRanges?.some((r) => r.symbol === 'Calculator.add')).toBe(true);
62
- });
63
-
64
- it('should keep interface definitions intact', () => {
65
- const sourceCode = `
66
- export interface User {
67
- id: string;
68
- name: string;
69
- email: string;
70
- }
71
- `;
72
-
73
- fs.writeFileSync(testFilePath, sourceCode);
74
- const { skeleton, lineRanges } = buildSkeletonForFile(testFilePath, tempDir);
75
-
76
- expect(skeleton).toContain('export interface User');
77
- expect(skeleton).toContain('id: string');
78
- expect(skeleton).toContain('name: string');
79
- expect(skeleton).toContain('email: string');
80
- expect(skeleton).toMatch(/\/\/ test\.ts:\d+/);
81
- expect(lineRanges?.some((r) => r.symbol === 'interface User')).toBe(true);
82
- });
83
-
84
- it('should keep import statements', () => {
85
- const sourceCode = `
86
- import { Something } from './somewhere';
87
- import * as fs from 'fs';
88
-
89
- export function doWork(): void {
90
- console.log('working');
91
- }
92
- `;
93
-
94
- fs.writeFileSync(testFilePath, sourceCode);
95
- const { skeleton } = buildSkeletonForFile(testFilePath, tempDir);
96
-
97
- expect(skeleton).toContain("import { Something } from './somewhere'");
98
- expect(skeleton).toContain("import * as fs from 'fs'");
99
- expect(skeleton).toContain('export function doWork(): void');
100
- expect(skeleton).not.toContain("console.log('working')");
101
- });
102
-
103
- it('should handle type aliases', () => {
104
- const sourceCode = `
105
- export type Status = 'active' | 'inactive' | 'pending';
106
- export type UserId = string;
107
- `;
108
-
109
- fs.writeFileSync(testFilePath, sourceCode);
110
- const { skeleton, lineRanges } = buildSkeletonForFile(testFilePath, tempDir);
111
-
112
- expect(skeleton).toContain("export type Status = 'active' | 'inactive' | 'pending'");
113
- expect(skeleton).toContain('export type UserId = string');
114
- expect(lineRanges?.some((r) => r.symbol === 'type Status')).toBe(true);
115
- });
116
-
117
- it('should handle functions with JSDoc', () => {
118
- const sourceCode = `
119
- /**
120
- * Calculates the sum of an array
121
- * @param numbers Array of numbers
122
- * @returns The sum
123
- */
124
- export function sum(numbers: number[]): number {
125
- return numbers.reduce((a, b) => a + b, 0);
126
- }
127
- `;
128
-
129
- fs.writeFileSync(testFilePath, sourceCode);
130
- const { skeleton } = buildSkeletonForFile(testFilePath, tempDir);
131
-
132
- expect(skeleton).toContain('Calculates the sum');
133
- expect(skeleton).toContain('export function sum(numbers: number[]): number');
134
- expect(skeleton).toContain('/* trimmed */');
135
- expect(skeleton).not.toContain('reduce');
136
- });
137
-
138
- it('should handle malformed TypeScript gracefully', () => {
139
- const sourceCode = 'export const x = {{{';
140
-
141
- fs.writeFileSync(testFilePath, sourceCode);
142
- const { skeleton } = buildSkeletonForFile(testFilePath, tempDir);
143
-
144
- // ts-morph is robust and may still parse partial content
145
- // Just verify it returns some output without crashing
146
- expect(skeleton).toBeDefined();
147
- expect(skeleton.length).toBeGreaterThan(0);
148
- });
149
- });
@@ -1,17 +0,0 @@
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>
@@ -1,23 +0,0 @@
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
- }
@@ -1,6 +0,0 @@
1
- export default {
2
- plugins: {
3
- tailwindcss: {},
4
- autoprefixer: {},
5
- },
6
- }
@@ -1,45 +0,0 @@
1
- import Navbar from './components/Navbar'
2
- import Hero from './components/Hero'
3
- import Problem from './components/Problem'
4
- import TokenSavings from './components/TokenSavings'
5
- import HowItWorks from './components/HowItWorks'
6
- import Features from './components/Features'
7
- import LanguageSupport from './components/LanguageSupport'
8
- import Install from './components/Install'
9
- import CliReference from './components/CliReference'
10
- import WorksWith from './components/WorksWith'
11
- import AgentMode from './components/AgentMode'
12
- import Footer from './components/Footer'
13
-
14
- export default function App() {
15
- return (
16
- <div className="relative min-h-screen overflow-x-hidden bg-bg text-white font-sans">
17
- <div
18
- className="pointer-events-none fixed inset-0 -z-10"
19
- aria-hidden
20
- >
21
- <div
22
- className="absolute -left-[20%] top-[10%] h-[520px] w-[520px] rounded-full bg-accent/[0.07] blur-[120px] motion-safe:animate-drift"
23
- />
24
- <div
25
- 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]"
26
- />
27
- <div
28
- 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]"
29
- />
30
- </div>
31
- <Navbar />
32
- <Hero />
33
- <Problem />
34
- <TokenSavings />
35
- <HowItWorks />
36
- <Features />
37
- <LanguageSupport />
38
- <Install />
39
- <CliReference />
40
- <WorksWith />
41
- <AgentMode />
42
- <Footer />
43
- </div>
44
- )
45
- }
@@ -1,45 +0,0 @@
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>$ skannr-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 &lt;query&gt;</span> Search for symbols in the codebase
27
- {'\n'} <span className="text-white">/symbol &lt;id&gt;</span> Get full implementation of a symbol
28
- {'\n'} <span className="text-white">/deps &lt;filePath&gt;</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
- }
@@ -1,89 +0,0 @@
1
- import Reveal from './Reveal'
2
-
3
- const commands = [
4
- ['skannr "<question>"', 'Ask about the codebase (positional argument)'],
5
- ['skannr risk', 'Check downstream impact and risk of uncommitted changes'],
6
- ['skannr risk --diff <path>', 'Analyze a specific diff/patch file'],
7
- ['skannr risk -n <hops>', 'Set max traversal hops (default: 2)'],
8
- ['skannr risk --json', 'JSON output for CI pipelines'],
9
- ['skannr report', 'Print repository health summary as JSON'],
10
- ['skannr agent', 'Interactive exploration mode'],
11
- ['skannr cache stats', 'Show cache hit/miss statistics'],
12
- ['skannr cache clear', 'Clear all cached analysis results'],
13
- ]
14
-
15
- const flags = [
16
- ['--root <path>', 'Project root (default: current directory)'],
17
- ['-n, --limit <number>', 'Number of top files to return (default: 10)'],
18
- ['--json', 'Shortcut for --format json'],
19
- ['--format <fmt>', 'human | markdown | json (default: human)'],
20
- ['--lang <mode>', 'typescript | javascript | python | auto (default: auto)'],
21
- ['--modules <keys>', 'Comma-separated module keys (auto-discovered when omitted)'],
22
- ['--watch', 'Watch the tree and re-run analysis when files change'],
23
- ['--skip-cache', 'Skip cache and force a full analysis'],
24
- ['--with-mapping', 'Generate symbol mapping for on-demand retrieval'],
25
- ['--mcp', 'Run as Model Context Protocol stdio server'],
26
- ['--telemetry-on / --telemetry-off', 'Toggle anonymous flag-only telemetry'],
27
- ]
28
-
29
- export default function CliReference() {
30
- return (
31
- <section className="py-24 px-5">
32
- <div className="max-w-5xl mx-auto">
33
- <Reveal>
34
- <h2 className="text-3xl md:text-5xl font-bold text-center tracking-tight">Commands & options.</h2>
35
- </Reveal>
36
-
37
- <Reveal delay={80}>
38
- <h3 className="mt-12 mb-4 text-xl font-semibold text-white/80">Commands</h3>
39
- <div className="overflow-hidden rounded-xl border border-border bg-card transition-colors duration-300 hover:border-white/10">
40
- <table className="w-full text-left">
41
- <thead className="border-b border-white/5">
42
- <tr className="text-[#888] text-sm">
43
- <th className="px-6 py-4 font-medium">Command</th>
44
- <th className="px-6 py-4 font-medium">Description</th>
45
- </tr>
46
- </thead>
47
- <tbody>
48
- {commands.map(([cmd, description]) => (
49
- <tr
50
- key={cmd}
51
- className="border-b border-white/5 transition-colors duration-200 last:border-b-0 hover:bg-white/[0.03]"
52
- >
53
- <td className="px-6 py-4 font-mono text-accent">{cmd}</td>
54
- <td className="px-6 py-4 text-[#d0d0d0]">{description}</td>
55
- </tr>
56
- ))}
57
- </tbody>
58
- </table>
59
- </div>
60
- </Reveal>
61
-
62
- <Reveal delay={160}>
63
- <h3 className="mt-10 mb-4 text-xl font-semibold text-white/80">Options</h3>
64
- <div className="overflow-hidden rounded-xl border border-border bg-card transition-colors duration-300 hover:border-white/10">
65
- <table className="w-full text-left">
66
- <thead className="border-b border-white/5">
67
- <tr className="text-[#888] text-sm">
68
- <th className="px-6 py-4 font-medium">Flag</th>
69
- <th className="px-6 py-4 font-medium">Description</th>
70
- </tr>
71
- </thead>
72
- <tbody>
73
- {flags.map(([flag, description]) => (
74
- <tr
75
- key={flag}
76
- className="border-b border-white/5 transition-colors duration-200 last:border-b-0 hover:bg-white/[0.03]"
77
- >
78
- <td className="px-6 py-4 font-mono text-accent">{flag}</td>
79
- <td className="px-6 py-4 text-[#d0d0d0]">{description}</td>
80
- </tr>
81
- ))}
82
- </tbody>
83
- </table>
84
- </div>
85
- </Reveal>
86
- </div>
87
- </section>
88
- )
89
- }
@@ -1,88 +0,0 @@
1
- import {
2
- AlertTriangle,
3
- Code2,
4
- Database,
5
- FileSearch,
6
- Network,
7
- Plug,
8
- RefreshCw,
9
- ShieldCheck,
10
- Zap,
11
- } from 'lucide-react'
12
- import Reveal from './Reveal'
13
-
14
- const features = [
15
- {
16
- icon: Network,
17
- title: 'Hybrid Retrieval',
18
- body: 'Lexical + structural + dependency-graph ranking. Finds architecturally central files, not just keyword matches.',
19
- },
20
- {
21
- icon: Zap,
22
- title: '96.5% Token Reduction',
23
- body: 'Skeleton generation strips bodies while preserving signatures and types. Feed entire codebases to your AI without hitting limits.',
24
- },
25
- {
26
- icon: AlertTriangle,
27
- title: 'Risk Analysis',
28
- body: 'Run "skannr risk" before pushing. Traverses the dependency graph, finds downstream affected files, flags untested code, and scores risk 0-10. Deterministic and instant.',
29
- },
30
- {
31
- icon: Code2,
32
- title: 'Auto Language Detection',
33
- body: "Detects the repo's dominant language automatically. TypeScript, JavaScript, and Python supported. Generic fallback for everything else.",
34
- },
35
- {
36
- icon: Database,
37
- title: 'Smart Caching',
38
- body: 'MD5-based file hashing detects changes automatically. Repeated queries run in milliseconds. 24-hour TTL with manual controls.',
39
- },
40
- {
41
- icon: FileSearch,
42
- title: 'Grounded Citations',
43
- body: 'Every response includes an Evidence section listing the exact files and symbols used. Verify AI answers by tracing to source.',
44
- },
45
- {
46
- icon: Plug,
47
- title: 'MCP Server Built In',
48
- body: 'Runs as a Model Context Protocol server. Plug into Gemini CLI, Claude Code, Cursor, or any MCP-compatible tool.',
49
- },
50
- {
51
- icon: RefreshCw,
52
- title: 'Watch Mode',
53
- body: 'Use --watch on large repos you touch daily. Skannr debounces file changes and re-analyzes with a fresh run (cache bypassed per pass) so output stays current.',
54
- },
55
- {
56
- icon: ShieldCheck,
57
- title: 'Opt-in Telemetry',
58
- body: 'Anonymous, flag-only usage stats if you enable them. No code, questions, or paths leave your machine. Turn on or off anytime with --telemetry-on / --telemetry-off.',
59
- },
60
- ]
61
-
62
- export default function Features() {
63
- return (
64
- <section id="features" className="py-24 px-5">
65
- <div className="max-w-6xl mx-auto">
66
- <Reveal>
67
- <h2 className="text-3xl md:text-5xl font-bold text-center tracking-tight">
68
- Everything you need. Nothing you don't.
69
- </h2>
70
- </Reveal>
71
- <div className="mt-14 grid grid-cols-1 md:grid-cols-2 lg:grid-cols-3 gap-5">
72
- {features.map(({ icon: Icon, title, body }, i) => (
73
- <Reveal key={title} delay={i * 70} className="h-full">
74
- <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)]">
75
- <Icon
76
- size={24}
77
- className="mb-4 text-accent transition-transform duration-300 group-hover:scale-110 group-hover:rotate-3"
78
- />
79
- <h3 className="mb-2 text-xl font-semibold">{title}</h3>
80
- <p className="text-[#888]">{body}</p>
81
- </article>
82
- </Reveal>
83
- ))}
84
- </div>
85
- </div>
86
- </section>
87
- )
88
- }
@@ -1,35 +0,0 @@
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
- }
@@ -1,125 +0,0 @@
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
- '$ skannr "how does authentication work?"',
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 · Watch mode · 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
- Skannr helps AI assistants understand entire codebases using structural
85
- skeletons and hybrid ranking. Human, Markdown, or JSON output; optional watch mode for
86
- live re-analysis; MCP for IDE tools—all without shipping your source off the CLI.
87
- </p>
88
-
89
- <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]">
90
- <a
91
- href="#install"
92
- 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"
93
- >
94
- Get started
95
- </a>
96
- <a
97
- href="https://github.com/7vignesh/code-analyzer"
98
- 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"
99
- >
100
- View on GitHub
101
- </a>
102
- </div>
103
-
104
- <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)]">
105
- <div className="flex items-center gap-2 px-4 py-3 border-b border-white/5">
106
- <span className="w-3 h-3 rounded-full bg-[#ff5f57]" />
107
- <span className="w-3 h-3 rounded-full bg-[#febc2e]" />
108
- <span className="w-3 h-3 rounded-full bg-[#28c840]" />
109
- <span className="ml-2 text-xs font-mono text-[#888]">bash</span>
110
- </div>
111
- <pre className="p-5 overflow-x-auto font-mono text-sm leading-7">
112
- {lines.map((_, idx) => {
113
- const current = displayed[idx] ?? ''
114
- const showCursor = !done && idx === displayed.length - 1
115
- return (
116
- <div key={`line-${idx}`} className="min-h-6">
117
- {renderLine(current, showCursor)}
118
- </div>
119
- )
120
- })}
121
- </pre>
122
- </div>
123
- </section>
124
- )
125
- }