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.
Files changed (142) hide show
  1. package/.eslintrc.js +22 -0
  2. package/README.md +109 -0
  3. package/dist/agent-cli.d.ts +7 -0
  4. package/dist/agent-cli.d.ts.map +1 -0
  5. package/dist/agent-cli.js +364 -0
  6. package/dist/agent-cli.js.map +1 -0
  7. package/dist/agent.d.ts +115 -0
  8. package/dist/agent.d.ts.map +1 -0
  9. package/dist/agent.js +340 -0
  10. package/dist/agent.js.map +1 -0
  11. package/dist/benchmark.d.ts +53 -0
  12. package/dist/benchmark.d.ts.map +1 -0
  13. package/dist/benchmark.js +307 -0
  14. package/dist/benchmark.js.map +1 -0
  15. package/dist/cache.d.ts +97 -0
  16. package/dist/cache.d.ts.map +1 -0
  17. package/dist/cache.js +284 -0
  18. package/dist/cache.js.map +1 -0
  19. package/dist/cli.d.ts +6 -0
  20. package/dist/cli.d.ts.map +1 -0
  21. package/dist/cli.js +238 -0
  22. package/dist/cli.js.map +1 -0
  23. package/dist/config.d.ts +8 -0
  24. package/dist/config.d.ts.map +1 -0
  25. package/dist/config.js +52 -0
  26. package/dist/config.js.map +1 -0
  27. package/dist/index.d.ts +18 -0
  28. package/dist/index.d.ts.map +1 -0
  29. package/dist/index.js +176 -0
  30. package/dist/index.js.map +1 -0
  31. package/dist/languages/GenericAdapter.d.ts +10 -0
  32. package/dist/languages/GenericAdapter.d.ts.map +1 -0
  33. package/dist/languages/GenericAdapter.js +41 -0
  34. package/dist/languages/GenericAdapter.js.map +1 -0
  35. package/dist/languages/LanguageAdapter.d.ts +14 -0
  36. package/dist/languages/LanguageAdapter.d.ts.map +1 -0
  37. package/dist/languages/LanguageAdapter.js +3 -0
  38. package/dist/languages/LanguageAdapter.js.map +1 -0
  39. package/dist/languages/PythonAdapter.d.ts +10 -0
  40. package/dist/languages/PythonAdapter.d.ts.map +1 -0
  41. package/dist/languages/PythonAdapter.js +98 -0
  42. package/dist/languages/PythonAdapter.js.map +1 -0
  43. package/dist/languages/TypeScriptAdapter.d.ts +17 -0
  44. package/dist/languages/TypeScriptAdapter.d.ts.map +1 -0
  45. package/dist/languages/TypeScriptAdapter.js +321 -0
  46. package/dist/languages/TypeScriptAdapter.js.map +1 -0
  47. package/dist/languages/registry.d.ts +4 -0
  48. package/dist/languages/registry.d.ts.map +1 -0
  49. package/dist/languages/registry.js +86 -0
  50. package/dist/languages/registry.js.map +1 -0
  51. package/dist/mapper.d.ts +49 -0
  52. package/dist/mapper.d.ts.map +1 -0
  53. package/dist/mapper.js +386 -0
  54. package/dist/mapper.js.map +1 -0
  55. package/dist/ranker-enhanced.d.ts +37 -0
  56. package/dist/ranker-enhanced.d.ts.map +1 -0
  57. package/dist/ranker-enhanced.js +395 -0
  58. package/dist/ranker-enhanced.js.map +1 -0
  59. package/dist/ranker.d.ts +14 -0
  60. package/dist/ranker.d.ts.map +1 -0
  61. package/dist/ranker.js +105 -0
  62. package/dist/ranker.js.map +1 -0
  63. package/dist/rocket-chat-scope.d.ts +7 -0
  64. package/dist/rocket-chat-scope.d.ts.map +1 -0
  65. package/dist/rocket-chat-scope.js +95 -0
  66. package/dist/rocket-chat-scope.js.map +1 -0
  67. package/dist/scanner.d.ts +16 -0
  68. package/dist/scanner.d.ts.map +1 -0
  69. package/dist/scanner.js +228 -0
  70. package/dist/scanner.js.map +1 -0
  71. package/dist/skeletonizer.d.ts +5 -0
  72. package/dist/skeletonizer.d.ts.map +1 -0
  73. package/dist/skeletonizer.js +52 -0
  74. package/dist/skeletonizer.js.map +1 -0
  75. package/dist/tokenizer.d.ts +9 -0
  76. package/dist/tokenizer.d.ts.map +1 -0
  77. package/dist/tokenizer.js +21 -0
  78. package/dist/tokenizer.js.map +1 -0
  79. package/dist/types.d.ts +68 -0
  80. package/dist/types.d.ts.map +1 -0
  81. package/dist/types.js +6 -0
  82. package/dist/types.js.map +1 -0
  83. package/gemini-extension/GEMINI.md +26 -0
  84. package/gemini-extension/gemini-extension.json +12 -0
  85. package/gemini-extension/package.json +14 -0
  86. package/gemini-extension/src/server.ts +63 -0
  87. package/gemini-extension/tsconfig.json +14 -0
  88. package/jest.config.js +5 -0
  89. package/package.json +46 -0
  90. package/src/agent-cli.ts +383 -0
  91. package/src/agent.ts +344 -0
  92. package/src/benchmark.ts +389 -0
  93. package/src/cache.ts +317 -0
  94. package/src/cli.ts +223 -0
  95. package/src/config.ts +22 -0
  96. package/src/index.ts +215 -0
  97. package/src/languages/GenericAdapter.ts +44 -0
  98. package/src/languages/LanguageAdapter.ts +14 -0
  99. package/src/languages/PythonAdapter.ts +74 -0
  100. package/src/languages/TypeScriptAdapter.ts +338 -0
  101. package/src/languages/registry.ts +49 -0
  102. package/src/mapper.ts +448 -0
  103. package/src/ranker-enhanced.ts +460 -0
  104. package/src/ranker.ts +92 -0
  105. package/src/scanner.ts +201 -0
  106. package/src/skeletonizer.ts +16 -0
  107. package/src/tokenizer.ts +20 -0
  108. package/src/types.ts +71 -0
  109. package/tests/agent.tools.test.ts +81 -0
  110. package/tests/benchmark.test.ts +31 -0
  111. package/tests/fixtures/sample.py +17 -0
  112. package/tests/fixtures/sample.ts +13 -0
  113. package/tests/fixtures/src/api/routes.ts +1 -0
  114. package/tests/fixtures/src/auth/permission.ts +3 -0
  115. package/tests/ranker-enhanced.test.ts +68 -0
  116. package/tests/ranker.test.ts +75 -0
  117. package/tests/scanner.scope.test.ts +41 -0
  118. package/tests/setup-fixtures.js +29 -0
  119. package/tests/skeletonizer.test.ts +142 -0
  120. package/tsconfig.json +21 -0
  121. package/uca-landing/index.html +17 -0
  122. package/uca-landing/package.json +23 -0
  123. package/uca-landing/postcss.config.js +6 -0
  124. package/uca-landing/src/App.jsx +43 -0
  125. package/uca-landing/src/components/AgentMode.jsx +45 -0
  126. package/uca-landing/src/components/CliReference.jsx +49 -0
  127. package/uca-landing/src/components/Features.jsx +63 -0
  128. package/uca-landing/src/components/Footer.jsx +35 -0
  129. package/uca-landing/src/components/Hero.jsx +124 -0
  130. package/uca-landing/src/components/HowItWorks.jsx +60 -0
  131. package/uca-landing/src/components/Install.jsx +90 -0
  132. package/uca-landing/src/components/LanguageSupport.jsx +63 -0
  133. package/uca-landing/src/components/Navbar.jsx +86 -0
  134. package/uca-landing/src/components/Problem.jsx +51 -0
  135. package/uca-landing/src/components/Reveal.jsx +40 -0
  136. package/uca-landing/src/components/WorksWith.jsx +59 -0
  137. package/uca-landing/src/hooks/useScrollNav.js +13 -0
  138. package/uca-landing/src/hooks/useTypewriter.js +41 -0
  139. package/uca-landing/src/index.css +13 -0
  140. package/uca-landing/src/main.jsx +10 -0
  141. package/uca-landing/tailwind.config.js +68 -0
  142. package/uca-landing/vite.config.js +6 -0
@@ -0,0 +1,338 @@
1
+ import { Project, SourceFile } from 'ts-morph';
2
+ import * as path from 'path';
3
+ import { LanguageAdapter, Symbol } from './LanguageAdapter';
4
+
5
+ export class TypeScriptAdapter implements LanguageAdapter {
6
+ name = 'typescript';
7
+ extensions = ['.ts', '.tsx', '.js', '.jsx', '.mjs', '.cjs'];
8
+
9
+ canHandle(filePath: string): boolean {
10
+ const ext = path.extname(filePath).toLowerCase();
11
+ return this.extensions.includes(ext);
12
+ }
13
+
14
+ generateSkeleton(content: string, filePath: string): string {
15
+ try {
16
+ const sourceFile = this.createSourceFile(content, filePath);
17
+ return this.generateSkeletonFromSourceFile(sourceFile);
18
+ } catch (error) {
19
+ return `/* Failed to parse file: ${error instanceof Error ? error.message : 'Unknown error'} */`;
20
+ }
21
+ }
22
+
23
+ extractSymbols(content: string): Symbol[] {
24
+ try {
25
+ const sourceFile = this.createSourceFile(content, 'memory.ts');
26
+ const symbols: Symbol[] = [];
27
+
28
+ for (const cls of sourceFile.getClasses()) {
29
+ symbols.push({
30
+ name: cls.getName() || 'Anonymous',
31
+ kind: 'class',
32
+ line: cls.getStartLineNumber(),
33
+ });
34
+ }
35
+
36
+ for (const func of sourceFile.getFunctions()) {
37
+ symbols.push({
38
+ name: func.getName() || 'anonymous',
39
+ kind: 'function',
40
+ line: func.getStartLineNumber(),
41
+ });
42
+ }
43
+
44
+ for (const iface of sourceFile.getInterfaces()) {
45
+ symbols.push({
46
+ name: iface.getName(),
47
+ kind: 'interface',
48
+ line: iface.getStartLineNumber(),
49
+ });
50
+ }
51
+
52
+ for (const typeAlias of sourceFile.getTypeAliases()) {
53
+ symbols.push({
54
+ name: typeAlias.getName(),
55
+ kind: 'type',
56
+ line: typeAlias.getStartLineNumber(),
57
+ });
58
+ }
59
+
60
+ for (const varStmt of sourceFile.getVariableStatements()) {
61
+ for (const decl of varStmt.getDeclarations()) {
62
+ symbols.push({
63
+ name: decl.getName(),
64
+ kind: 'variable',
65
+ line: decl.getStartLineNumber(),
66
+ });
67
+ }
68
+ }
69
+
70
+ const exported = new Set<string>();
71
+ sourceFile.getExportedDeclarations().forEach((_, name) => exported.add(name));
72
+ for (const name of exported) {
73
+ symbols.push({ name, kind: 'export', line: 1 });
74
+ }
75
+
76
+ return symbols;
77
+ } catch {
78
+ return [];
79
+ }
80
+ }
81
+
82
+ extractImports(content: string): string[] {
83
+ try {
84
+ const sourceFile = this.createSourceFile(content, 'memory.ts');
85
+ return sourceFile.getImportDeclarations().map((imp) => imp.getModuleSpecifierValue());
86
+ } catch {
87
+ return [];
88
+ }
89
+ }
90
+
91
+ private createSourceFile(content: string, filePath: string): SourceFile {
92
+ const project = new Project({
93
+ useInMemoryFileSystem: true,
94
+ skipAddingFilesFromTsConfig: true,
95
+ compilerOptions: {
96
+ allowJs: true,
97
+ checkJs: false,
98
+ },
99
+ });
100
+ return project.createSourceFile(filePath, content, { overwrite: true });
101
+ }
102
+
103
+ private generateSkeletonFromSourceFile(sourceFile: SourceFile): string {
104
+ const lines: string[] = [];
105
+ lines.push(`/* Skeleton of ${path.basename(sourceFile.getFilePath())} */\n`);
106
+
107
+ const imports = sourceFile.getImportDeclarations();
108
+ for (const imp of imports) {
109
+ lines.push(imp.getText());
110
+ }
111
+
112
+ if (imports.length > 0) {
113
+ lines.push('');
114
+ }
115
+
116
+ const exportDeclarations = sourceFile.getExportDeclarations();
117
+ const exportAssignments = sourceFile.getExportAssignments();
118
+
119
+ const classes = sourceFile.getClasses();
120
+ for (const cls of classes) {
121
+ lines.push(this.processClass(cls));
122
+ lines.push('');
123
+ }
124
+
125
+ const interfaces = sourceFile.getInterfaces();
126
+ for (const iface of interfaces) {
127
+ lines.push(iface.getText());
128
+ lines.push('');
129
+ }
130
+
131
+ const typeAliases = sourceFile.getTypeAliases();
132
+ for (const typeAlias of typeAliases) {
133
+ lines.push(typeAlias.getText());
134
+ lines.push('');
135
+ }
136
+
137
+ const enums = sourceFile.getEnums();
138
+ for (const enumDecl of enums) {
139
+ lines.push(enumDecl.getText());
140
+ lines.push('');
141
+ }
142
+
143
+ const functions = sourceFile.getFunctions();
144
+ for (const func of functions) {
145
+ lines.push(this.processFunction(func));
146
+ lines.push('');
147
+ }
148
+
149
+ const variables = sourceFile.getVariableStatements();
150
+ for (const varStatement of variables) {
151
+ lines.push(this.processVariableStatement(varStatement));
152
+ lines.push('');
153
+ }
154
+
155
+ for (const exportDecl of exportDeclarations) {
156
+ lines.push(exportDecl.getText());
157
+ }
158
+
159
+ for (const exportAssign of exportAssignments) {
160
+ lines.push(exportAssign.getText());
161
+ }
162
+
163
+ return lines.join('\n').trim();
164
+ }
165
+
166
+ private processClass(cls: any): string {
167
+ const lines: string[] = [];
168
+
169
+ const modifiers = cls.getModifiers().map((m: any) => m.getText()).join(' ');
170
+ let classDecl = modifiers ? `${modifiers} class` : 'class';
171
+ classDecl += ` ${cls.getName() || 'Anonymous'}`;
172
+
173
+ const typeParams = cls.getTypeParameters();
174
+ if (typeParams.length > 0) {
175
+ classDecl += `<${typeParams.map((tp: any) => tp.getText()).join(', ')}>`;
176
+ }
177
+
178
+ const extendsClause = cls.getExtends();
179
+ if (extendsClause) {
180
+ classDecl += ` extends ${extendsClause.getText()}`;
181
+ }
182
+
183
+ const implementsClauses = cls.getImplements();
184
+ if (implementsClauses.length > 0) {
185
+ classDecl += ` implements ${implementsClauses.map((ic: any) => ic.getText()).join(', ')}`;
186
+ }
187
+
188
+ classDecl += ' {';
189
+ lines.push(classDecl);
190
+
191
+ const jsDoc = cls.getJsDocs();
192
+ if (jsDoc.length > 0) {
193
+ lines.splice(0, 0, jsDoc[0].getText());
194
+ }
195
+
196
+ const properties = cls.getProperties();
197
+ for (const prop of properties) {
198
+ const propModifiers = prop.getModifiers().map((m: any) => m.getText()).join(' ');
199
+ const propName = prop.getName();
200
+ const propType = prop.getType().getText();
201
+ const propLine = propModifiers
202
+ ? ` ${propModifiers} ${propName}: ${propType};`
203
+ : ` ${propName}: ${propType};`;
204
+ lines.push(propLine);
205
+ }
206
+
207
+ if (properties.length > 0) {
208
+ lines.push('');
209
+ }
210
+
211
+ const methods = cls.getMethods();
212
+ for (const method of methods) {
213
+ lines.push(this.processMethod(method));
214
+ }
215
+
216
+ const constructors = cls.getConstructors();
217
+ for (const ctor of constructors) {
218
+ lines.push(this.processConstructor(ctor));
219
+ }
220
+
221
+ lines.push('}');
222
+ return lines.join('\n');
223
+ }
224
+
225
+ private processMethod(method: any): string {
226
+ const lines: string[] = [];
227
+ const jsDoc = method.getJsDocs();
228
+ if (jsDoc.length > 0) {
229
+ lines.push(' ' + jsDoc[0].getText().split('\n').join('\n '));
230
+ }
231
+
232
+ const modifiers = method.getModifiers().map((m: any) => m.getText()).join(' ');
233
+ const name = method.getName();
234
+ const params = method.getParameters().map((p: any) => {
235
+ const pName = p.getName();
236
+ const pType = p.getType().getText();
237
+ const optional = p.isOptional() ? '?' : '';
238
+ return `${pName}${optional}: ${pType}`;
239
+ }).join(', ');
240
+
241
+ const returnType = method.getReturnType().getText();
242
+
243
+ let signature = modifiers ? ` ${modifiers} ${name}` : ` ${name}`;
244
+ signature += `(${params}): ${returnType} {`;
245
+ lines.push(signature);
246
+ lines.push(' /* trimmed */');
247
+ lines.push(' }');
248
+ lines.push('');
249
+
250
+ return lines.join('\n');
251
+ }
252
+
253
+ private processConstructor(ctor: any): string {
254
+ const lines: string[] = [];
255
+
256
+ const jsDoc = ctor.getJsDocs();
257
+ if (jsDoc.length > 0) {
258
+ lines.push(' ' + jsDoc[0].getText().split('\n').join('\n '));
259
+ }
260
+
261
+ const params = ctor.getParameters().map((p: any) => {
262
+ const modifiers = p.getModifiers().map((m: any) => m.getText()).join(' ');
263
+ const pName = p.getName();
264
+ const pType = p.getType().getText();
265
+ const optional = p.isOptional() ? '?' : '';
266
+ const paramStr = `${pName}${optional}: ${pType}`;
267
+ return modifiers ? `${modifiers} ${paramStr}` : paramStr;
268
+ }).join(', ');
269
+
270
+ lines.push(` constructor(${params}) {`);
271
+ lines.push(' /* trimmed */');
272
+ lines.push(' }');
273
+ lines.push('');
274
+ return lines.join('\n');
275
+ }
276
+
277
+ private processFunction(func: any): string {
278
+ const lines: string[] = [];
279
+ const jsDoc = func.getJsDocs();
280
+ if (jsDoc.length > 0) {
281
+ lines.push(jsDoc[0].getText());
282
+ }
283
+
284
+ const modifiers = func.getModifiers().map((m: any) => m.getText()).join(' ');
285
+ const name = func.getName();
286
+ const params = func.getParameters().map((p: any) => {
287
+ const pName = p.getName();
288
+ const pType = p.getType().getText();
289
+ const optional = p.isOptional() ? '?' : '';
290
+ return `${pName}${optional}: ${pType}`;
291
+ }).join(', ');
292
+
293
+ const returnType = func.getReturnType().getText();
294
+
295
+ let signature = modifiers ? `${modifiers} function` : 'function';
296
+ signature += ` ${name}(${params}): ${returnType} {`;
297
+ lines.push(signature);
298
+ lines.push(' /* trimmed */');
299
+ lines.push('}');
300
+
301
+ return lines.join('\n');
302
+ }
303
+
304
+ private processVariableStatement(varStatement: any): string {
305
+ const lines: string[] = [];
306
+ const jsDoc = varStatement.getJsDocs();
307
+ if (jsDoc.length > 0) {
308
+ lines.push(jsDoc[0].getText());
309
+ }
310
+
311
+ const modifiers = varStatement.getModifiers().map((m: any) => m.getText()).join(' ');
312
+ const declarations = varStatement.getDeclarations();
313
+ const declarationKind = varStatement.getDeclarationKind();
314
+
315
+ for (const decl of declarations) {
316
+ const name = decl.getName();
317
+ const type = decl.getType().getText();
318
+ const initializer = decl.getInitializer();
319
+
320
+ let value = '';
321
+ if (initializer) {
322
+ const initText = initializer.getText();
323
+ if (initText.length < 50 && !initText.includes('{') && !initText.includes('=>')) {
324
+ value = ` = ${initText}`;
325
+ } else {
326
+ value = ' = /* trimmed */';
327
+ }
328
+ }
329
+
330
+ const line = modifiers
331
+ ? `${modifiers} ${declarationKind} ${name}: ${type}${value};`
332
+ : `${declarationKind} ${name}: ${type}${value};`;
333
+ lines.push(line);
334
+ }
335
+
336
+ return lines.join('\n');
337
+ }
338
+ }
@@ -0,0 +1,49 @@
1
+ import { LanguageAdapter } from './LanguageAdapter';
2
+ import { TypeScriptAdapter } from './TypeScriptAdapter';
3
+ import { PythonAdapter } from './PythonAdapter';
4
+ import { GenericAdapter } from './GenericAdapter';
5
+ import * as path from 'path';
6
+
7
+ const adapters: LanguageAdapter[] = [
8
+ new TypeScriptAdapter(),
9
+ new PythonAdapter(),
10
+ ];
11
+
12
+ const generic = new GenericAdapter();
13
+
14
+ export function getAdapter(filePath: string): LanguageAdapter {
15
+ const ext = path.extname(filePath).toLowerCase();
16
+ return adapters.find((a) => a.extensions.includes(ext)) ?? generic;
17
+ }
18
+
19
+ export function detectRepoLanguages(root: string): string[] {
20
+ const fs = require('fs');
21
+ const extCount: Record<string, number> = {};
22
+ walkAndCount(root, extCount, 0, 3);
23
+ return Object.entries(extCount)
24
+ .sort((a, b) => b[1] - a[1])
25
+ .slice(0, 3)
26
+ .map(([ext]) => ext);
27
+ }
28
+
29
+ function walkAndCount(dir: string, counts: Record<string, number>, depth: number, maxDepth: number): void {
30
+ if (depth > maxDepth) return;
31
+ const fs = require('fs');
32
+ const path = require('path');
33
+ const ignored = new Set(['node_modules', '.git', 'dist', 'build', 'vendor', '__pycache__']);
34
+ try {
35
+ for (const entry of fs.readdirSync(dir)) {
36
+ if (ignored.has(entry)) continue;
37
+ const full = path.join(dir, entry);
38
+ const stat = fs.statSync(full);
39
+ if (stat.isDirectory()) {
40
+ walkAndCount(full, counts, depth + 1, maxDepth);
41
+ } else {
42
+ const ext = path.extname(entry).toLowerCase();
43
+ if (ext) counts[ext] = (counts[ext] ?? 0) + 1;
44
+ }
45
+ }
46
+ } catch {
47
+ // Ignore unreadable directories.
48
+ }
49
+ }