@arcteninc/core 0.0.176 ā 0.0.177
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/README.md +73 -78
- package/dist/index.cjs +3 -16
- package/dist/index.d.ts +1 -6
- package/dist/index.d.ts.map +1 -1
- package/dist/index.mjs +851 -8410
- package/dist/lib/useAgent.d.ts +1 -2
- package/dist/lib/useAgent.d.ts.map +1 -1
- package/dist/types/use-agent.d.ts +3 -44
- package/dist/types/use-agent.d.ts.map +1 -1
- package/dist/utils/extract-tool-metadata.d.ts.map +1 -1
- package/package.json +7 -46
- package/scripts/arcten-cli.cjs +14 -108
- package/scripts/cli-extract-types-auto.ts +22 -4
- package/scripts/update-core.cjs +124 -0
- package/dist/components/ArctenAgent.d.ts +0 -52
- package/dist/components/ArctenAgent.d.ts.map +0 -1
- package/dist/components/ai-elements/prompt-input.d.ts +0 -187
- package/dist/components/ai-elements/prompt-input.d.ts.map +0 -1
- package/dist/components/ai-elements/reasoning.d.ts +0 -17
- package/dist/components/ai-elements/reasoning.d.ts.map +0 -1
- package/dist/components/ai-elements/response.d.ts +0 -8
- package/dist/components/ai-elements/response.d.ts.map +0 -1
- package/dist/components/ai-elements/shimmer.d.ts +0 -10
- package/dist/components/ai-elements/shimmer.d.ts.map +0 -1
- package/dist/components/citation-button.d.ts +0 -14
- package/dist/components/citation-button.d.ts.map +0 -1
- package/dist/components/citation-text-renderer.d.ts +0 -31
- package/dist/components/citation-text-renderer.d.ts.map +0 -1
- package/dist/components/secure-modals/EmailModal.d.ts +0 -10
- package/dist/components/secure-modals/EmailModal.d.ts.map +0 -1
- package/dist/components/secure-modals/FormModal.d.ts +0 -20
- package/dist/components/secure-modals/FormModal.d.ts.map +0 -1
- package/dist/components/secure-modals/PasswordModal.d.ts +0 -10
- package/dist/components/secure-modals/PasswordModal.d.ts.map +0 -1
- package/dist/components/secure-modals/PhoneModal.d.ts +0 -10
- package/dist/components/secure-modals/PhoneModal.d.ts.map +0 -1
- package/dist/components/secure-modals/PinModal.d.ts +0 -11
- package/dist/components/secure-modals/PinModal.d.ts.map +0 -1
- package/dist/components/secure-modals/SecureModalProvider.d.ts +0 -13
- package/dist/components/secure-modals/SecureModalProvider.d.ts.map +0 -1
- package/dist/components/secure-modals/TextModal.d.ts +0 -11
- package/dist/components/secure-modals/TextModal.d.ts.map +0 -1
- package/dist/components/secure-modals/index.d.ts +0 -10
- package/dist/components/secure-modals/index.d.ts.map +0 -1
- package/dist/components/secure-modals/types.d.ts +0 -34
- package/dist/components/secure-modals/types.d.ts.map +0 -1
- package/dist/components/tool-call-approval.d.ts +0 -9
- package/dist/components/tool-call-approval.d.ts.map +0 -1
- package/dist/components/tool-call-result.d.ts +0 -8
- package/dist/components/tool-call-result.d.ts.map +0 -1
- package/dist/components/ui/autotextarea.d.ts +0 -19
- package/dist/components/ui/autotextarea.d.ts.map +0 -1
- package/dist/components/ui/badge.d.ts +0 -10
- package/dist/components/ui/badge.d.ts.map +0 -1
- package/dist/components/ui/button.d.ts +0 -14
- package/dist/components/ui/button.d.ts.map +0 -1
- package/dist/components/ui/collapsible.d.ts +0 -6
- package/dist/components/ui/collapsible.d.ts.map +0 -1
- package/dist/components/ui/command.d.ts +0 -19
- package/dist/components/ui/command.d.ts.map +0 -1
- package/dist/components/ui/dialog.d.ts +0 -16
- package/dist/components/ui/dialog.d.ts.map +0 -1
- package/dist/components/ui/dropdown-menu.d.ts +0 -26
- package/dist/components/ui/dropdown-menu.d.ts.map +0 -1
- package/dist/components/ui/hover-card.d.ts +0 -7
- package/dist/components/ui/hover-card.d.ts.map +0 -1
- package/dist/components/ui/input-group.d.ts +0 -17
- package/dist/components/ui/input-group.d.ts.map +0 -1
- package/dist/components/ui/input.d.ts +0 -4
- package/dist/components/ui/input.d.ts.map +0 -1
- package/dist/components/ui/kbd.d.ts +0 -4
- package/dist/components/ui/kbd.d.ts.map +0 -1
- package/dist/components/ui/select.d.ts +0 -16
- package/dist/components/ui/select.d.ts.map +0 -1
- package/dist/components/ui/textarea.d.ts +0 -4
- package/dist/components/ui/textarea.d.ts.map +0 -1
- package/dist/components/ui/tooltip.d.ts +0 -8
- package/dist/components/ui/tooltip.d.ts.map +0 -1
- package/dist/core.css +0 -1
- package/dist/utils/form-generator.d.ts +0 -29
- package/dist/utils/form-generator.d.ts.map +0 -1
- package/dist/utils/secure-param-detector.d.ts +0 -26
- package/dist/utils/secure-param-detector.d.ts.map +0 -1
- package/scripts/cli-agent-inject.ts +0 -205
- package/scripts/cli-agent-wrapper.cjs +0 -51
- package/scripts/cli-agent.ts +0 -483
- package/scripts/cli-create-project.ts +0 -608
- package/scripts/cli-create-wrapper.cjs +0 -60
- package/scripts/cli-init-wizard-wrapper.cjs +0 -58
- package/scripts/cli-init-wizard.ts +0 -646
- package/scripts/cli-prompt-wrapper.cjs +0 -51
- package/scripts/cli-prompt.ts +0 -306
- package/scripts/cli-sync-wrapper.cjs +0 -69
- package/scripts/cli-sync.ts +0 -915
- package/scripts/cli-tools-wrapper.cjs +0 -51
- package/scripts/cli-tools.ts +0 -320
- package/scripts/cli-uninstall-wrapper.cjs +0 -66
- package/scripts/cli-uninstall.ts +0 -173
- package/scripts/config-parser.ts +0 -432
- package/scripts/dashboard-sync.ts +0 -454
- package/scripts/tree-sitter-discover.ts +0 -526
- package/scripts/wasm/tree-sitter-tsx.wasm +0 -0
- package/scripts/wasm/tree-sitter-typescript.wasm +0 -0
|
@@ -1,526 +0,0 @@
|
|
|
1
|
-
#!/usr/bin/env node
|
|
2
|
-
/**
|
|
3
|
-
* Fast function discovery using tree-sitter
|
|
4
|
-
* Scans TypeScript/TSX files for ALL functions (exported + private)
|
|
5
|
-
* 5-10x faster than TypeScript compiler for initial discovery
|
|
6
|
-
*
|
|
7
|
-
* Key: Discovers both exported and non-exported functions
|
|
8
|
-
* - isExported: true = can be imported from anywhere
|
|
9
|
-
* - isExported: false = only accessible within the file
|
|
10
|
-
*/
|
|
11
|
-
|
|
12
|
-
import * as fs from 'fs';
|
|
13
|
-
import * as path from 'path';
|
|
14
|
-
import { glob } from 'glob';
|
|
15
|
-
|
|
16
|
-
// tree-sitter types
|
|
17
|
-
interface TreeSitterParser {
|
|
18
|
-
parse(input: string): SyntaxTree;
|
|
19
|
-
setLanguage(language: Language): void;
|
|
20
|
-
}
|
|
21
|
-
|
|
22
|
-
interface Language {}
|
|
23
|
-
|
|
24
|
-
interface SyntaxTree {
|
|
25
|
-
rootNode: SyntaxNode;
|
|
26
|
-
}
|
|
27
|
-
|
|
28
|
-
interface SyntaxNode {
|
|
29
|
-
type: string;
|
|
30
|
-
text: string;
|
|
31
|
-
children: SyntaxNode[];
|
|
32
|
-
namedChildren: SyntaxNode[];
|
|
33
|
-
childForFieldName(name: string): SyntaxNode | null;
|
|
34
|
-
descendantsOfType(type: string | string[]): SyntaxNode[];
|
|
35
|
-
firstChild: SyntaxNode | null;
|
|
36
|
-
nextSibling: SyntaxNode | null;
|
|
37
|
-
startPosition: { row: number; column: number };
|
|
38
|
-
endPosition: { row: number; column: number };
|
|
39
|
-
}
|
|
40
|
-
|
|
41
|
-
export interface DiscoveredFunction {
|
|
42
|
-
name: string;
|
|
43
|
-
kind: 'function' | 'arrow' | 'variable' | 'class';
|
|
44
|
-
file: string;
|
|
45
|
-
line: number;
|
|
46
|
-
hasParameters: boolean;
|
|
47
|
-
isAsync: boolean;
|
|
48
|
-
isExported: boolean; // true = can be imported, false = private to file
|
|
49
|
-
jsDocComment?: string;
|
|
50
|
-
}
|
|
51
|
-
|
|
52
|
-
// Backwards compatibility alias
|
|
53
|
-
export type DiscoveredExport = DiscoveredFunction;
|
|
54
|
-
|
|
55
|
-
let Parser: any = null;
|
|
56
|
-
let TypeScriptLanguage: Language | null = null;
|
|
57
|
-
let TSXLanguage: Language | null = null;
|
|
58
|
-
|
|
59
|
-
async function initTreeSitter(): Promise<boolean> {
|
|
60
|
-
if (Parser) return true;
|
|
61
|
-
|
|
62
|
-
// Use web-tree-sitter (WASM) - most compatible across Node/Bun/Windows
|
|
63
|
-
try {
|
|
64
|
-
const TreeSitterModule = await import('web-tree-sitter');
|
|
65
|
-
const TreeSitter = TreeSitterModule.default || TreeSitterModule;
|
|
66
|
-
|
|
67
|
-
// In web-tree-sitter 0.25+, init is a static method on Parser class
|
|
68
|
-
const ParserClass = TreeSitter.Parser || TreeSitter;
|
|
69
|
-
|
|
70
|
-
if (typeof ParserClass.init === 'function') {
|
|
71
|
-
await ParserClass.init();
|
|
72
|
-
}
|
|
73
|
-
|
|
74
|
-
Parser = ParserClass;
|
|
75
|
-
|
|
76
|
-
// Load TypeScript and TSX language WASM files
|
|
77
|
-
// First try local wasm files, then CDN
|
|
78
|
-
const scriptDir = typeof __dirname !== 'undefined'
|
|
79
|
-
? __dirname
|
|
80
|
-
: path.dirname(new URL(import.meta.url).pathname).replace(/^\/([A-Z]:)/, '$1'); // Fix Windows paths
|
|
81
|
-
|
|
82
|
-
const wasmDir = path.join(scriptDir, 'wasm');
|
|
83
|
-
const Language = TreeSitter.Language || Parser.Language;
|
|
84
|
-
|
|
85
|
-
const tsWasmPath = path.join(wasmDir, 'tree-sitter-typescript.wasm');
|
|
86
|
-
const tsxWasmPath = path.join(wasmDir, 'tree-sitter-tsx.wasm');
|
|
87
|
-
|
|
88
|
-
if (fs.existsSync(tsWasmPath) && fs.existsSync(tsxWasmPath)) {
|
|
89
|
-
TypeScriptLanguage = await Language.load(tsWasmPath);
|
|
90
|
-
TSXLanguage = await Language.load(tsxWasmPath);
|
|
91
|
-
} else {
|
|
92
|
-
// Download WASM files from CDN
|
|
93
|
-
console.log('ā³ Downloading tree-sitter language files...');
|
|
94
|
-
|
|
95
|
-
const tsWasmUrl = 'https://unpkg.com/tree-sitter-typescript@0.23.2/tree-sitter-typescript.wasm';
|
|
96
|
-
const tsxWasmUrl = 'https://unpkg.com/tree-sitter-typescript@0.23.2/tree-sitter-tsx.wasm';
|
|
97
|
-
|
|
98
|
-
// Create wasm directory if it doesn't exist
|
|
99
|
-
if (!fs.existsSync(wasmDir)) {
|
|
100
|
-
fs.mkdirSync(wasmDir, { recursive: true });
|
|
101
|
-
}
|
|
102
|
-
|
|
103
|
-
// Download and save WASM files
|
|
104
|
-
const tsResponse = await fetch(tsWasmUrl);
|
|
105
|
-
const tsxResponse = await fetch(tsxWasmUrl);
|
|
106
|
-
|
|
107
|
-
if (!tsResponse.ok || !tsxResponse.ok) {
|
|
108
|
-
throw new Error('Failed to download WASM files');
|
|
109
|
-
}
|
|
110
|
-
|
|
111
|
-
const tsBuffer = Buffer.from(await tsResponse.arrayBuffer());
|
|
112
|
-
const tsxBuffer = Buffer.from(await tsxResponse.arrayBuffer());
|
|
113
|
-
|
|
114
|
-
fs.writeFileSync(tsWasmPath, tsBuffer);
|
|
115
|
-
fs.writeFileSync(tsxWasmPath, tsxBuffer);
|
|
116
|
-
|
|
117
|
-
console.log('ā Tree-sitter languages downloaded');
|
|
118
|
-
|
|
119
|
-
TypeScriptLanguage = await Language.load(tsWasmPath);
|
|
120
|
-
TSXLanguage = await Language.load(tsxWasmPath);
|
|
121
|
-
}
|
|
122
|
-
|
|
123
|
-
return true;
|
|
124
|
-
} catch (error) {
|
|
125
|
-
console.error('Failed to initialize tree-sitter:', error);
|
|
126
|
-
}
|
|
127
|
-
|
|
128
|
-
return false;
|
|
129
|
-
}
|
|
130
|
-
|
|
131
|
-
function getParser(isTsx: boolean): TreeSitterParser {
|
|
132
|
-
const parser = new Parser();
|
|
133
|
-
parser.setLanguage(isTsx ? TSXLanguage : TypeScriptLanguage);
|
|
134
|
-
return parser;
|
|
135
|
-
}
|
|
136
|
-
|
|
137
|
-
/**
|
|
138
|
-
* Extract JSDoc comment from a node if present
|
|
139
|
-
*/
|
|
140
|
-
function extractJsDoc(node: SyntaxNode): string | undefined {
|
|
141
|
-
let sibling = node.firstChild;
|
|
142
|
-
// Look for comment nodes before the declaration
|
|
143
|
-
const comments: string[] = [];
|
|
144
|
-
|
|
145
|
-
// Actually need to look at previous siblings
|
|
146
|
-
let prev = node;
|
|
147
|
-
while (prev) {
|
|
148
|
-
const parent = prev;
|
|
149
|
-
// In tree-sitter, comments are usually siblings
|
|
150
|
-
break;
|
|
151
|
-
}
|
|
152
|
-
|
|
153
|
-
// Look for comment child
|
|
154
|
-
for (const child of node.children) {
|
|
155
|
-
if (child.type === 'comment') {
|
|
156
|
-
const text = child.text;
|
|
157
|
-
if (text.startsWith('/**')) {
|
|
158
|
-
return text
|
|
159
|
-
.replace(/^\/\*\*\s*/, '')
|
|
160
|
-
.replace(/\s*\*\/$/, '')
|
|
161
|
-
.replace(/^\s*\*\s?/gm, '')
|
|
162
|
-
.trim();
|
|
163
|
-
}
|
|
164
|
-
}
|
|
165
|
-
}
|
|
166
|
-
|
|
167
|
-
return undefined;
|
|
168
|
-
}
|
|
169
|
-
|
|
170
|
-
/**
|
|
171
|
-
* Check if a node has an export modifier
|
|
172
|
-
*/
|
|
173
|
-
function hasExportKeyword(node: SyntaxNode): boolean {
|
|
174
|
-
for (const child of node.children) {
|
|
175
|
-
if (child.type === 'export' || child.text === 'export') {
|
|
176
|
-
return true;
|
|
177
|
-
}
|
|
178
|
-
}
|
|
179
|
-
return false;
|
|
180
|
-
}
|
|
181
|
-
|
|
182
|
-
/**
|
|
183
|
-
* Check if a function is async
|
|
184
|
-
*/
|
|
185
|
-
function isAsyncFunction(node: SyntaxNode): boolean {
|
|
186
|
-
for (const child of node.children) {
|
|
187
|
-
if (child.type === 'async' || child.text === 'async') {
|
|
188
|
-
return true;
|
|
189
|
-
}
|
|
190
|
-
}
|
|
191
|
-
return false;
|
|
192
|
-
}
|
|
193
|
-
|
|
194
|
-
/**
|
|
195
|
-
* Check if a function has parameters (excluding empty params)
|
|
196
|
-
*/
|
|
197
|
-
function hasParameters(node: SyntaxNode): boolean {
|
|
198
|
-
const params = node.childForFieldName('parameters');
|
|
199
|
-
if (!params) return false;
|
|
200
|
-
|
|
201
|
-
// Filter out just parentheses
|
|
202
|
-
const paramChildren = params.namedChildren;
|
|
203
|
-
return paramChildren.length > 0;
|
|
204
|
-
}
|
|
205
|
-
|
|
206
|
-
/**
|
|
207
|
-
* Extract function name from various declaration patterns
|
|
208
|
-
*/
|
|
209
|
-
function extractFunctionName(node: SyntaxNode): string | null {
|
|
210
|
-
// Direct function name
|
|
211
|
-
const nameNode = node.childForFieldName('name');
|
|
212
|
-
if (nameNode) {
|
|
213
|
-
return nameNode.text;
|
|
214
|
-
}
|
|
215
|
-
|
|
216
|
-
// For variable declarations: export const foo = ...
|
|
217
|
-
if (node.type === 'variable_declarator') {
|
|
218
|
-
const name = node.childForFieldName('name');
|
|
219
|
-
return name?.text || null;
|
|
220
|
-
}
|
|
221
|
-
|
|
222
|
-
return null;
|
|
223
|
-
}
|
|
224
|
-
|
|
225
|
-
/**
|
|
226
|
-
* Discover ALL functions in a file using tree-sitter (exported + private)
|
|
227
|
-
*/
|
|
228
|
-
export async function discoverFunctionsInFile(filePath: string): Promise<DiscoveredFunction[]> {
|
|
229
|
-
const initialized = await initTreeSitter();
|
|
230
|
-
if (!initialized) return [];
|
|
231
|
-
|
|
232
|
-
const content = fs.readFileSync(filePath, 'utf-8');
|
|
233
|
-
const isTsx = filePath.endsWith('.tsx');
|
|
234
|
-
const parser = getParser(isTsx);
|
|
235
|
-
const tree = parser.parse(content);
|
|
236
|
-
|
|
237
|
-
const functions: DiscoveredFunction[] = [];
|
|
238
|
-
const rootNode = tree.rootNode;
|
|
239
|
-
|
|
240
|
-
function processNode(node: SyntaxNode, isInsideExport: boolean = false) {
|
|
241
|
-
// === EXPORTED FUNCTIONS ===
|
|
242
|
-
// export function foo() {} or export const foo = () => {}
|
|
243
|
-
if (node.type === 'export_statement') {
|
|
244
|
-
const declaration = node.childForFieldName('declaration');
|
|
245
|
-
if (!declaration) {
|
|
246
|
-
// Could be export { ... } or export default - skip re-exports
|
|
247
|
-
return;
|
|
248
|
-
}
|
|
249
|
-
|
|
250
|
-
if (declaration.type === 'function_declaration') {
|
|
251
|
-
const name = extractFunctionName(declaration);
|
|
252
|
-
if (name) {
|
|
253
|
-
functions.push({
|
|
254
|
-
name,
|
|
255
|
-
kind: 'function',
|
|
256
|
-
file: filePath,
|
|
257
|
-
line: node.startPosition.row + 1,
|
|
258
|
-
hasParameters: hasParameters(declaration),
|
|
259
|
-
isAsync: isAsyncFunction(declaration),
|
|
260
|
-
isExported: true,
|
|
261
|
-
jsDocComment: extractJsDoc(node),
|
|
262
|
-
});
|
|
263
|
-
}
|
|
264
|
-
}
|
|
265
|
-
|
|
266
|
-
// export const foo = () => {} or export const foo = function() {}
|
|
267
|
-
if (declaration.type === 'lexical_declaration') {
|
|
268
|
-
for (const child of declaration.namedChildren) {
|
|
269
|
-
if (child.type === 'variable_declarator') {
|
|
270
|
-
const name = child.childForFieldName('name')?.text;
|
|
271
|
-
const value = child.childForFieldName('value');
|
|
272
|
-
|
|
273
|
-
if (name && value) {
|
|
274
|
-
const isArrow = value.type === 'arrow_function';
|
|
275
|
-
const isFunc = value.type === 'function_expression' || value.type === 'function';
|
|
276
|
-
|
|
277
|
-
if (isArrow || isFunc) {
|
|
278
|
-
functions.push({
|
|
279
|
-
name,
|
|
280
|
-
kind: isArrow ? 'arrow' : 'function',
|
|
281
|
-
file: filePath,
|
|
282
|
-
line: node.startPosition.row + 1,
|
|
283
|
-
hasParameters: hasParameters(value),
|
|
284
|
-
isAsync: isAsyncFunction(value),
|
|
285
|
-
isExported: true,
|
|
286
|
-
jsDocComment: extractJsDoc(node),
|
|
287
|
-
});
|
|
288
|
-
}
|
|
289
|
-
}
|
|
290
|
-
}
|
|
291
|
-
}
|
|
292
|
-
}
|
|
293
|
-
|
|
294
|
-
// export class Foo {}
|
|
295
|
-
if (declaration.type === 'class_declaration') {
|
|
296
|
-
const name = extractFunctionName(declaration);
|
|
297
|
-
if (name) {
|
|
298
|
-
functions.push({
|
|
299
|
-
name,
|
|
300
|
-
kind: 'class',
|
|
301
|
-
file: filePath,
|
|
302
|
-
line: node.startPosition.row + 1,
|
|
303
|
-
hasParameters: false,
|
|
304
|
-
isAsync: false,
|
|
305
|
-
isExported: true,
|
|
306
|
-
jsDocComment: extractJsDoc(node),
|
|
307
|
-
});
|
|
308
|
-
}
|
|
309
|
-
}
|
|
310
|
-
|
|
311
|
-
// Don't process children of export statements (already handled)
|
|
312
|
-
return;
|
|
313
|
-
}
|
|
314
|
-
|
|
315
|
-
// === NON-EXPORTED (PRIVATE) FUNCTIONS ===
|
|
316
|
-
// function foo() {} (without export)
|
|
317
|
-
if (node.type === 'function_declaration' && !isInsideExport) {
|
|
318
|
-
const name = extractFunctionName(node);
|
|
319
|
-
if (name) {
|
|
320
|
-
functions.push({
|
|
321
|
-
name,
|
|
322
|
-
kind: 'function',
|
|
323
|
-
file: filePath,
|
|
324
|
-
line: node.startPosition.row + 1,
|
|
325
|
-
hasParameters: hasParameters(node),
|
|
326
|
-
isAsync: isAsyncFunction(node),
|
|
327
|
-
isExported: false,
|
|
328
|
-
jsDocComment: extractJsDoc(node),
|
|
329
|
-
});
|
|
330
|
-
}
|
|
331
|
-
}
|
|
332
|
-
|
|
333
|
-
// const foo = () => {} or const foo = function() {} (without export)
|
|
334
|
-
if (node.type === 'lexical_declaration' && !isInsideExport) {
|
|
335
|
-
for (const child of node.namedChildren) {
|
|
336
|
-
if (child.type === 'variable_declarator') {
|
|
337
|
-
const name = child.childForFieldName('name')?.text;
|
|
338
|
-
const value = child.childForFieldName('value');
|
|
339
|
-
|
|
340
|
-
if (name && value) {
|
|
341
|
-
const isArrow = value.type === 'arrow_function';
|
|
342
|
-
const isFunc = value.type === 'function_expression' || value.type === 'function';
|
|
343
|
-
|
|
344
|
-
if (isArrow || isFunc) {
|
|
345
|
-
functions.push({
|
|
346
|
-
name,
|
|
347
|
-
kind: isArrow ? 'arrow' : 'function',
|
|
348
|
-
file: filePath,
|
|
349
|
-
line: node.startPosition.row + 1,
|
|
350
|
-
hasParameters: hasParameters(value),
|
|
351
|
-
isAsync: isAsyncFunction(value),
|
|
352
|
-
isExported: false,
|
|
353
|
-
jsDocComment: extractJsDoc(node),
|
|
354
|
-
});
|
|
355
|
-
}
|
|
356
|
-
}
|
|
357
|
-
}
|
|
358
|
-
}
|
|
359
|
-
}
|
|
360
|
-
|
|
361
|
-
// class Foo {} (without export)
|
|
362
|
-
if (node.type === 'class_declaration' && !isInsideExport) {
|
|
363
|
-
const name = extractFunctionName(node);
|
|
364
|
-
if (name) {
|
|
365
|
-
functions.push({
|
|
366
|
-
name,
|
|
367
|
-
kind: 'class',
|
|
368
|
-
file: filePath,
|
|
369
|
-
line: node.startPosition.row + 1,
|
|
370
|
-
hasParameters: false,
|
|
371
|
-
isAsync: false,
|
|
372
|
-
isExported: false,
|
|
373
|
-
jsDocComment: extractJsDoc(node),
|
|
374
|
-
});
|
|
375
|
-
}
|
|
376
|
-
}
|
|
377
|
-
|
|
378
|
-
// Process children (but not inside class bodies to avoid methods)
|
|
379
|
-
if (node.type !== 'class_body') {
|
|
380
|
-
for (const child of node.namedChildren) {
|
|
381
|
-
processNode(child, false);
|
|
382
|
-
}
|
|
383
|
-
}
|
|
384
|
-
}
|
|
385
|
-
|
|
386
|
-
processNode(rootNode);
|
|
387
|
-
return functions;
|
|
388
|
-
}
|
|
389
|
-
|
|
390
|
-
// Backwards compatibility alias
|
|
391
|
-
export const discoverExportsInFile = discoverFunctionsInFile;
|
|
392
|
-
|
|
393
|
-
/**
|
|
394
|
-
* Discover ALL functions in a directory (exported + private)
|
|
395
|
-
*/
|
|
396
|
-
export async function discoverFunctionsInDirectory(
|
|
397
|
-
directory: string,
|
|
398
|
-
options: {
|
|
399
|
-
ignore?: string[];
|
|
400
|
-
functionsOnly?: boolean;
|
|
401
|
-
exportedOnly?: boolean;
|
|
402
|
-
} = {}
|
|
403
|
-
): Promise<DiscoveredFunction[]> {
|
|
404
|
-
const ignore = options.ignore || ['**/node_modules/**', '**/dist/**', '**/.next/**', '**/build/**'];
|
|
405
|
-
|
|
406
|
-
const pattern = path.join(directory, '**/*.{ts,tsx}').replace(/\\/g, '/');
|
|
407
|
-
const files = await glob(pattern, { ignore });
|
|
408
|
-
|
|
409
|
-
console.log(`š Scanning ${files.length} files with tree-sitter...`);
|
|
410
|
-
|
|
411
|
-
const startTime = Date.now();
|
|
412
|
-
const allFunctions: DiscoveredFunction[] = [];
|
|
413
|
-
|
|
414
|
-
for (const file of files) {
|
|
415
|
-
const functions = await discoverFunctionsInFile(file);
|
|
416
|
-
allFunctions.push(...functions);
|
|
417
|
-
}
|
|
418
|
-
|
|
419
|
-
const elapsed = Date.now() - startTime;
|
|
420
|
-
const exported = allFunctions.filter(f => f.isExported).length;
|
|
421
|
-
const priv = allFunctions.filter(f => !f.isExported).length;
|
|
422
|
-
console.log(`ā Found ${allFunctions.length} functions (${exported} exported, ${priv} private) in ${elapsed}ms`);
|
|
423
|
-
|
|
424
|
-
let result = allFunctions;
|
|
425
|
-
|
|
426
|
-
// Filter to exported only if requested
|
|
427
|
-
if (options.exportedOnly) {
|
|
428
|
-
result = result.filter(f => f.isExported);
|
|
429
|
-
}
|
|
430
|
-
|
|
431
|
-
// Filter to functions only if requested
|
|
432
|
-
if (options.functionsOnly) {
|
|
433
|
-
result = result.filter(f => f.kind === 'function' || f.kind === 'arrow');
|
|
434
|
-
}
|
|
435
|
-
|
|
436
|
-
return result;
|
|
437
|
-
}
|
|
438
|
-
|
|
439
|
-
// Backwards compatibility alias
|
|
440
|
-
export const discoverExportsInDirectory = discoverFunctionsInDirectory;
|
|
441
|
-
|
|
442
|
-
/**
|
|
443
|
-
* Filter exports that look like they could be tools
|
|
444
|
-
* (functions with parameters, not utility helpers)
|
|
445
|
-
*/
|
|
446
|
-
export function filterLikelyTools(exports: DiscoveredExport[]): DiscoveredExport[] {
|
|
447
|
-
return exports.filter(exp => {
|
|
448
|
-
// Must be a function or arrow function
|
|
449
|
-
if (exp.kind !== 'function' && exp.kind !== 'arrow') {
|
|
450
|
-
return false;
|
|
451
|
-
}
|
|
452
|
-
|
|
453
|
-
// Must have parameters (tools need inputs)
|
|
454
|
-
if (!exp.hasParameters) {
|
|
455
|
-
return false;
|
|
456
|
-
}
|
|
457
|
-
|
|
458
|
-
// Skip specific React/utility patterns (NOT general prefixes like create/get)
|
|
459
|
-
const name = exp.name.toLowerCase();
|
|
460
|
-
|
|
461
|
-
// Exact patterns to skip (React hooks, contexts, HOCs)
|
|
462
|
-
const skipExactPatterns = [
|
|
463
|
-
/^use[A-Z]/, // React hooks: useState, useEffect, useCallback
|
|
464
|
-
/^with[A-Z]/, // HOCs: withRouter, withAuth
|
|
465
|
-
/^create(context|store|reducer|slice|action|selector|ref|portal)$/i, // React utilities
|
|
466
|
-
/^is[A-Z][a-z]*$/, // Short type guards: isArray, isNull (but not isValidEmail)
|
|
467
|
-
/^has(own|prototype)/i, // hasOwnProperty, hasPrototype
|
|
468
|
-
/^to(string|json|array|number|boolean)$/i, // Converters
|
|
469
|
-
/^from(string|json|array|entries)$/i, // Converters
|
|
470
|
-
/^(parse|stringify)(json|int|float)?$/i, // Parsers
|
|
471
|
-
/^(assert|throw|log|debug|trace|warn|error|console)/i, // Logging/errors
|
|
472
|
-
/^(emit|dispatch|subscribe|unsubscribe)$/i, // Event system
|
|
473
|
-
/^on[A-Z]/, // Event handlers: onClick, onChange
|
|
474
|
-
/^handle[A-Z]/, // Event handlers: handleClick, handleSubmit
|
|
475
|
-
/^_/, // Private functions
|
|
476
|
-
];
|
|
477
|
-
|
|
478
|
-
for (const pattern of skipExactPatterns) {
|
|
479
|
-
if (pattern.test(exp.name)) {
|
|
480
|
-
return false;
|
|
481
|
-
}
|
|
482
|
-
}
|
|
483
|
-
|
|
484
|
-
// Skip very short names (likely utilities)
|
|
485
|
-
if (exp.name.length < 4) {
|
|
486
|
-
return false;
|
|
487
|
-
}
|
|
488
|
-
|
|
489
|
-
return true;
|
|
490
|
-
});
|
|
491
|
-
}
|
|
492
|
-
|
|
493
|
-
// CLI entry point
|
|
494
|
-
if (import.meta.url === `file://${process.argv[1]}` || process.argv[1]?.endsWith('tree-sitter-discover.ts')) {
|
|
495
|
-
const args = process.argv.slice(2);
|
|
496
|
-
const directory = args[0] || process.cwd();
|
|
497
|
-
|
|
498
|
-
discoverFunctionsInDirectory(directory, { functionsOnly: true })
|
|
499
|
-
.then(functions => {
|
|
500
|
-
const tools = filterLikelyTools(functions);
|
|
501
|
-
|
|
502
|
-
const exported = tools.filter(t => t.isExported);
|
|
503
|
-
const priv = tools.filter(t => !t.isExported);
|
|
504
|
-
|
|
505
|
-
console.log('\nš¦ Exported functions (can be imported anywhere):');
|
|
506
|
-
if (exported.length === 0) {
|
|
507
|
-
console.log(' (none found)');
|
|
508
|
-
} else {
|
|
509
|
-
for (const tool of exported) {
|
|
510
|
-
console.log(` ā ${tool.name} (${path.basename(tool.file)}:${tool.line})`);
|
|
511
|
-
}
|
|
512
|
-
}
|
|
513
|
-
|
|
514
|
-
console.log('\nš Private functions (only in their file):');
|
|
515
|
-
if (priv.length === 0) {
|
|
516
|
-
console.log(' (none found)');
|
|
517
|
-
} else {
|
|
518
|
-
for (const tool of priv) {
|
|
519
|
-
console.log(` ⢠${tool.name} (${path.basename(tool.file)}:${tool.line})`);
|
|
520
|
-
}
|
|
521
|
-
}
|
|
522
|
-
|
|
523
|
-
console.log(`\nTotal: ${tools.length} likely tool functions`);
|
|
524
|
-
})
|
|
525
|
-
.catch(console.error);
|
|
526
|
-
}
|
|
Binary file
|
|
Binary file
|