@arcteninc/core 0.0.63 → 0.0.64

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/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@arcteninc/core",
3
- "version": "0.0.63",
3
+ "version": "0.0.64",
4
4
  "type": "module",
5
5
  "main": "./dist/index.cjs",
6
6
  "module": "./dist/index.mjs",
@@ -20,21 +20,19 @@
20
20
  },
21
21
  "sideEffects": false,
22
22
  "bin": {
23
- "arcten": "./scripts/arcten-cli.cjs"
23
+ "arcten": "./scripts/arcten-cli.cjs",
24
+ "arcten-extract-types": "./scripts/cli-extract-types-auto-wrapper.js"
24
25
  },
25
26
  "files": [
26
27
  "dist",
27
28
  "scripts/cli-extract-types-auto.ts",
28
- "scripts/cli-extract-types-auto.js",
29
- "scripts/arcten-cli.cjs",
30
- "scripts/postinstall-check-version.cjs",
31
- "scripts/update-core.cjs"
29
+ "scripts/cli-extract-types-auto-wrapper.js",
30
+ "scripts/arcten-cli.cjs"
32
31
  ],
33
32
  "scripts": {
34
33
  "dev": "vite build --watch",
35
34
  "build": "vite build",
36
- "prepublishOnly": "bun run build",
37
- "postinstall": "node scripts/postinstall-check-version.cjs"
35
+ "prepublishOnly": "bun run build"
38
36
  },
39
37
  "peerDependencies": {
40
38
  "ai": "^6.0.0-beta.94",
@@ -56,6 +54,7 @@
56
54
  "dependencies": {
57
55
  "ts-json-schema-generator": "^2.4.0",
58
56
  "typescript": "^5.9.3",
57
+ "tsx": "^4.19.2",
59
58
  "@ai-sdk/openai": "^3.0.0-beta.47",
60
59
  "@ai-sdk/react": "^3.0.0-beta.92",
61
60
  "@emotion/is-prop-valid": "^1.4.0",
@@ -14,9 +14,10 @@ const path = require('path');
14
14
  const fs = require('fs');
15
15
 
16
16
  const commands = {
17
- 'extract-types': () => require('./cli-extract-types-auto.js'),
18
- 'tools': () => require('./cli-extract-types-auto.js'), // Alias
19
- 'update': () => require('./update-core.js'),
17
+ 'extract-types': 'extract-types',
18
+ 'tools': 'extract-types', // Alias
19
+ 'setup': 'extract-types', // Alias - better name for extract-types
20
+ 'update': 'update',
20
21
  'help': showHelp,
21
22
  '--help': showHelp,
22
23
  '-h': showHelp,
@@ -29,18 +30,19 @@ function showHelp() {
29
30
  Usage: arcten <command> [options]
30
31
 
31
32
  Commands:
32
- extract-types, tools Extract tool metadata from your project
33
- Alias: arcten tools
33
+ extract-types, tools, setup Extract tool metadata from your project
34
+ Aliases: arcten tools, arcten setup
34
35
 
35
- update Update @arcteninc/core to latest version
36
- Updates package.json and shows next steps
36
+ update Update @arcteninc/core to latest version
37
+ Updates package.json and shows next steps
37
38
 
38
- help Show this help message
39
+ help Show this help message
39
40
 
40
41
  Examples:
41
42
  arcten tools Extract tool types (same as arcten extract-types)
42
- arcten update Update @arcteninc/core to latest version
43
- arcten help Show help
43
+ arcten setup Extract tool types (same as arcten extract-types)
44
+ arcten update Update @arcteninc/core to latest version
45
+ arcten help Show help
44
46
 
45
47
  For more information, visit https://github.com/arcteninc/core
46
48
  `);
@@ -66,28 +68,26 @@ function main() {
66
68
 
67
69
  try {
68
70
  const commandHandler = commands[command];
69
- if (typeof commandHandler === 'function' && commandHandler !== showHelp) {
70
- // For commands that are modules, we need to handle them differently
71
- // Since they're designed to run as standalone scripts, we'll spawn them
71
+
72
+ if (commandHandler === showHelp) {
73
+ // For help command
74
+ commandHandler();
75
+ return;
76
+ }
77
+
78
+ if (typeof commandHandler === 'string') {
79
+ // For commands that need to spawn scripts
72
80
  let scriptPath;
73
81
  let runner = 'node';
74
82
 
75
- if (command === 'update') {
76
- scriptPath = path.join(__dirname, 'update-core.cjs');
83
+ if (commandHandler === 'update') {
84
+ scriptPath = path.join(__dirname, 'update-core.js');
85
+ } else if (commandHandler === 'extract-types') {
86
+ // For extract-types/tools/setup, use the wrapper script which handles TypeScript execution
87
+ scriptPath = path.join(__dirname, 'cli-extract-types-auto-wrapper.js');
77
88
  } else {
78
- // For extract-types/tools, try .js first, fallback to .ts with bun
79
- const jsPath = path.join(__dirname, 'cli-extract-types-auto.js');
80
- const tsPath = path.join(__dirname, 'cli-extract-types-auto.ts');
81
-
82
- if (fs.existsSync(jsPath)) {
83
- scriptPath = jsPath;
84
- } else if (fs.existsSync(tsPath)) {
85
- scriptPath = tsPath;
86
- runner = 'bun'; // Use bun for TypeScript files
87
- } else {
88
- console.error(`❌ Script not found: ${jsPath} or ${tsPath}`);
89
- process.exit(1);
90
- }
89
+ console.error(`❌ Unknown command handler: ${commandHandler}`);
90
+ process.exit(1);
91
91
  }
92
92
 
93
93
  if (!fs.existsSync(scriptPath)) {
@@ -106,7 +106,7 @@ function main() {
106
106
  console.error(`❌ Failed to run command:`, error.message);
107
107
  if (runner === 'bun' && error.code === 'ENOENT') {
108
108
  console.error(`\n💡 Bun not found. Install it: https://bun.sh`);
109
- console.error(` Or ensure cli-extract-types-auto.js is compiled`);
109
+ console.error(` Or ensure tsx is available: npm install -g tsx`);
110
110
  }
111
111
  process.exit(1);
112
112
  });
@@ -115,8 +115,8 @@ function main() {
115
115
  process.exit(code || 0);
116
116
  });
117
117
  } else {
118
- // For help command
119
- commandHandler();
118
+ console.error(`❌ Invalid command handler for: ${command}`);
119
+ process.exit(1);
120
120
  }
121
121
  } catch (error) {
122
122
  console.error(`❌ Error running command:`, error.message);
@@ -0,0 +1,108 @@
1
+ #!/usr/bin/env node
2
+ /**
3
+ * Wrapper script that checks for bun first, then tsx, then falls back to node with tsx
4
+ * This ensures compatibility across different environments
5
+ */
6
+
7
+ const { spawn } = require('child_process');
8
+ const path = require('path');
9
+ const fs = require('fs');
10
+
11
+ const scriptPath = path.join(__dirname, 'cli-extract-types-auto.ts');
12
+ const args = process.argv.slice(2);
13
+
14
+ // Check if a command is available
15
+ function checkCommand(command) {
16
+ return new Promise((resolve) => {
17
+ const check = spawn(command, ['--version'], {
18
+ stdio: 'ignore',
19
+ shell: true
20
+ });
21
+
22
+ check.on('error', () => resolve(false));
23
+ check.on('close', (code) => resolve(code === 0));
24
+ });
25
+ }
26
+
27
+ // Check if tsx is available in node_modules
28
+ function findTsxInNodeModules() {
29
+ let currentDir = __dirname;
30
+ while (currentDir !== path.dirname(currentDir)) {
31
+ const tsxPath = path.join(currentDir, 'node_modules', '.bin', 'tsx');
32
+ if (fs.existsSync(tsxPath)) {
33
+ return tsxPath;
34
+ }
35
+ currentDir = path.dirname(currentDir);
36
+ }
37
+ return null;
38
+ }
39
+
40
+ async function run() {
41
+ // Try bun first (faster, native TypeScript support)
42
+ if (await checkCommand('bun')) {
43
+ const proc = spawn('bun', [scriptPath, ...args], {
44
+ stdio: 'inherit',
45
+ shell: true
46
+ });
47
+ proc.on('error', (err) => {
48
+ console.error('Error running with bun:', err.message);
49
+ process.exit(1);
50
+ });
51
+ proc.on('exit', (code) => {
52
+ process.exit(code || 0);
53
+ });
54
+ return;
55
+ }
56
+
57
+ // Try tsx from node_modules first (if installed as dependency)
58
+ const tsxPath = findTsxInNodeModules();
59
+ if (tsxPath) {
60
+ const proc = spawn(tsxPath, [scriptPath, ...args], {
61
+ stdio: 'inherit',
62
+ shell: true
63
+ });
64
+ proc.on('error', (err) => {
65
+ console.error('Error running with tsx:', err.message);
66
+ process.exit(1);
67
+ });
68
+ proc.on('exit', (code) => {
69
+ process.exit(code || 0);
70
+ });
71
+ return;
72
+ }
73
+
74
+ // Try global tsx
75
+ if (await checkCommand('tsx')) {
76
+ const proc = spawn('tsx', [scriptPath, ...args], {
77
+ stdio: 'inherit',
78
+ shell: true
79
+ });
80
+ proc.on('error', (err) => {
81
+ console.error('Error running with tsx:', err.message);
82
+ process.exit(1);
83
+ });
84
+ proc.on('exit', (code) => {
85
+ process.exit(code || 0);
86
+ });
87
+ return;
88
+ }
89
+
90
+ // Try npx tsx as last resort (will download tsx if needed)
91
+ const proc = spawn('npx', ['--yes', 'tsx', scriptPath, ...args], {
92
+ stdio: 'inherit',
93
+ shell: true
94
+ });
95
+ proc.on('error', (err) => {
96
+ console.error('Error running with npx tsx:', err.message);
97
+ console.error('\nPlease install one of the following:');
98
+ console.error(' - bun: https://bun.sh');
99
+ console.error(' - tsx: npm install -g tsx (or it will be installed via npx)');
100
+ process.exit(1);
101
+ });
102
+ proc.on('exit', (code) => {
103
+ process.exit(code || 0);
104
+ });
105
+ }
106
+
107
+ run();
108
+
@@ -1,4 +1,4 @@
1
- #!/usr/bin/env bun
1
+ #!/usr/bin/env node
2
2
  /**
3
3
  * Automatically discover and extract types for tools used in ArctenAgent/useAgent
4
4
  * Scans the project, finds all tool usages, and generates metadata only for used tools
@@ -83,6 +83,7 @@ async function findToolUsageFiles(projectRoot: string): Promise<string[]> {
83
83
  ignore: ['**/node_modules/**', '**/dist/**', '**/.next/**', '**/build/**'],
84
84
  });
85
85
 
86
+ console.log(`📂 Found ${files.length} TypeScript files to scan`);
86
87
  return files;
87
88
  }
88
89
 
@@ -92,8 +93,7 @@ async function findToolUsageFiles(projectRoot: string): Promise<string[]> {
92
93
  function extractToolNamesFromExpression(
93
94
  expr: ts.Expression,
94
95
  sourceFile: ts.SourceFile,
95
- variableMap: Map<string, ts.Expression>,
96
- program?: ts.Program
96
+ variableMap: Map<string, ts.Expression>
97
97
  ): { names: Set<string>; order: string[] } {
98
98
  const toolNames = new Set<string>();
99
99
  const toolOrder: string[] = []; // Preserve order
@@ -102,12 +102,6 @@ function extractToolNamesFromExpression(
102
102
  function extractFromExpr(node: ts.Node): void {
103
103
  if (visited.has(node)) return;
104
104
  visited.add(node);
105
-
106
- // Handle type assertions: (expr as any)
107
- if (ts.isAsExpression(node)) {
108
- extractFromExpr(node.expression);
109
- return;
110
- }
111
105
 
112
106
  // Direct array literal: [tool1, tool2]
113
107
  if (ts.isArrayLiteralExpression(node)) {
@@ -135,15 +129,9 @@ function extractToolNamesFromExpression(
135
129
  // Property access: tools.getOrders -> extract "getOrders"
136
130
  const propName = element.name.text;
137
131
  if (propName) {
138
- // Try to resolve the module to find the actual function name
139
- const resolvedName = resolvePropertyAccess(element, sourceFile, program);
140
- const finalName = resolvedName || propName;
141
- // Only add if it's a valid identifier name
142
- if (finalName && finalName !== 'undefined' && finalName !== 'null' && finalName !== 'any') {
143
- if (!toolNames.has(finalName)) {
144
- toolNames.add(finalName);
145
- toolOrder.push(finalName); // Preserve order
146
- }
132
+ if (!toolNames.has(propName)) {
133
+ toolNames.add(propName);
134
+ toolOrder.push(propName); // Preserve order
147
135
  }
148
136
  }
149
137
  } else if (ts.isElementAccessExpression(element)) {
@@ -152,12 +140,9 @@ function extractToolNamesFromExpression(
152
140
  if (ts.isStringLiteral(indexExpr) || ts.isNumericLiteral(indexExpr)) {
153
141
  const name = indexExpr.text;
154
142
  if (name && name !== 'undefined' && name !== 'null') {
155
- // Try to resolve the module
156
- const resolvedName = resolveElementAccess(element, sourceFile, program);
157
- const finalName = resolvedName || name;
158
- if (!toolNames.has(finalName)) {
159
- toolNames.add(finalName);
160
- toolOrder.push(finalName); // Preserve order
143
+ if (!toolNames.has(name)) {
144
+ toolNames.add(name);
145
+ toolOrder.push(name); // Preserve order
161
146
  }
162
147
  }
163
148
  } else {
@@ -192,18 +177,12 @@ function extractToolNamesFromExpression(
192
177
  return;
193
178
  }
194
179
 
195
- // Property access: wrappedTools.getRAGInfo or tools.getLocation
180
+ // Property access: wrappedTools.getRAGInfo
196
181
  if (ts.isPropertyAccessExpression(node)) {
197
182
  const propName = node.name.text;
198
- // Try to resolve the module to find the actual function name
199
- const resolvedName = resolvePropertyAccess(node, sourceFile, program);
200
- const finalName = resolvedName || propName;
201
- // Only add if it's a valid identifier name (not empty, not a keyword)
202
- if (finalName && finalName !== 'undefined' && finalName !== 'null' && finalName !== 'any') {
203
- if (!toolNames.has(finalName)) {
204
- toolNames.add(finalName);
205
- toolOrder.push(finalName);
206
- }
183
+ if (!toolNames.has(propName)) {
184
+ toolNames.add(propName);
185
+ toolOrder.push(propName);
207
186
  }
208
187
  return;
209
188
  }
@@ -213,20 +192,26 @@ function extractToolNamesFromExpression(
213
192
  const callExpr = node.expression;
214
193
  if (ts.isIdentifier(callExpr)) {
215
194
  const funcName = callExpr.text;
216
- if (funcName === 'useMemo') {
217
- const memoizedExpr = extractToolsFromUseMemo(node, sourceFile, variableMap);
218
- if (memoizedExpr) {
219
- extractFromExpr(memoizedExpr);
195
+ if (funcName === 'useMemo' && node.arguments.length > 0) {
196
+ const firstArg = node.arguments[0];
197
+ // Arrow function: () => [...]
198
+ if (ts.isArrowFunction(firstArg) && firstArg.body) {
199
+ if (ts.isBlock(firstArg.body)) {
200
+ // Block body: () => { return [...] }
201
+ for (const stmt of firstArg.body.statements) {
202
+ if (ts.isReturnStatement(stmt) && stmt.expression) {
203
+ extractFromExpr(stmt.expression);
204
+ }
205
+ }
206
+ } else {
207
+ // Expression body: () => [...]
208
+ extractFromExpr(firstArg.body);
209
+ }
210
+ }
211
+ // Regular function call: useMemo(fn, [])
212
+ else if (ts.isFunctionExpression(firstArg) || ts.isArrowFunction(firstArg)) {
213
+ // Can't easily extract from function body without more analysis
220
214
  }
221
- }
222
- }
223
- // Also handle other function calls that might return arrays
224
- // For example: someFunction() that returns an array of tools
225
- if (node.arguments.length === 0) {
226
- // Check if this call might be a variable reference
227
- const varExpr = variableMap.get(callExpr.getText(sourceFile));
228
- if (varExpr) {
229
- extractFromExpr(varExpr);
230
215
  }
231
216
  }
232
217
  return;
@@ -243,60 +228,8 @@ function extractToolNamesFromExpression(
243
228
  return { names: toolNames, order: toolOrder };
244
229
  }
245
230
 
246
- /**
247
- * Resolve property access like tools.getLocation to find the actual function name
248
- * Returns the resolved name if found, or null if couldn't resolve
249
- */
250
- function resolvePropertyAccess(
251
- expr: ts.PropertyAccessExpression,
252
- sourceFile: ts.SourceFile,
253
- program?: ts.Program
254
- ): string | null {
255
- if (!program) return null;
256
-
257
- const checker = program.getTypeChecker();
258
- const symbol = checker.getSymbolAtLocation(expr);
259
-
260
- if (symbol) {
261
- // Get the name of the property (e.g., "getLocation")
262
- return symbol.getName();
263
- }
264
-
265
- // Fallback: try to resolve the object (e.g., "tools")
266
- const objectExpr = expr.expression;
267
- if (ts.isIdentifier(objectExpr)) {
268
- const objectName = objectExpr.text;
269
- // Check if this is an imported module (e.g., import * as tools from "./tools")
270
- // We'll handle this in the import resolution
271
- return null;
272
- }
273
-
274
- return null;
275
- }
276
-
277
- /**
278
- * Resolve element access like tools['getLocation'] to find the actual function name
279
- */
280
- function resolveElementAccess(
281
- expr: ts.ElementAccessExpression,
282
- sourceFile: ts.SourceFile,
283
- program?: ts.Program
284
- ): string | null {
285
- if (!program) return null;
286
-
287
- const checker = program.getTypeChecker();
288
- const symbol = checker.getSymbolAtLocation(expr);
289
-
290
- if (symbol) {
291
- return symbol.getName();
292
- }
293
-
294
- return null;
295
- }
296
-
297
231
  /**
298
232
  * Build a map of variable declarations in the file
299
- * Handles: const x = [...], const x = useMemo(...), etc.
300
233
  */
301
234
  function buildVariableMap(sourceFile: ts.SourceFile): Map<string, ts.Expression> {
302
235
  const variableMap = new Map<string, ts.Expression>();
@@ -325,58 +258,6 @@ function buildVariableMap(sourceFile: ts.SourceFile): Map<string, ts.Expression>
325
258
  return variableMap;
326
259
  }
327
260
 
328
- /**
329
- * Extract tools from useMemo callback, handling both arrow functions and regular functions
330
- * Also handles type assertions like `as any`
331
- */
332
- function extractToolsFromUseMemo(
333
- useMemoCall: ts.CallExpression,
334
- sourceFile: ts.SourceFile,
335
- variableMap: Map<string, ts.Expression>
336
- ): ts.Expression | null {
337
- if (useMemoCall.arguments.length === 0) return null;
338
-
339
- const firstArg = useMemoCall.arguments[0];
340
-
341
- function extractFromBody(body: ts.Expression | ts.Block): ts.Expression | null {
342
- if (ts.isBlock(body)) {
343
- // Block body: () => { return [...] }
344
- for (const stmt of body.statements) {
345
- if (ts.isReturnStatement(stmt) && stmt.expression) {
346
- return unwrapTypeAssertion(stmt.expression);
347
- }
348
- }
349
- } else {
350
- // Expression body: () => [...]
351
- return unwrapTypeAssertion(body);
352
- }
353
- return null;
354
- }
355
-
356
- // Arrow function: () => [...]
357
- if (ts.isArrowFunction(firstArg)) {
358
- if (firstArg.body) {
359
- return extractFromBody(firstArg.body);
360
- }
361
- }
362
- // Regular function: function() { return [...] }
363
- else if (ts.isFunctionExpression(firstArg) && firstArg.body) {
364
- return extractFromBody(firstArg.body);
365
- }
366
-
367
- return null;
368
- }
369
-
370
- /**
371
- * Unwrap type assertions like `as any`, `as ToolFunction[]`, etc.
372
- */
373
- function unwrapTypeAssertion(expr: ts.Expression): ts.Expression {
374
- if (ts.isAsExpression(expr)) {
375
- return expr.expression;
376
- }
377
- return expr;
378
- }
379
-
380
261
  /**
381
262
  * Extract tool names from ArctenAgent or useAgent usage
382
263
  */
@@ -407,7 +288,7 @@ function extractToolNamesFromFile(
407
288
  if (attr.initializer && ts.isJsxExpression(attr.initializer)) {
408
289
  const expr = attr.initializer.expression;
409
290
  if (expr) {
410
- const extracted = extractToolNamesFromExpression(expr, sourceFile, variableMap, program);
291
+ const extracted = extractToolNamesFromExpression(expr, sourceFile, variableMap);
411
292
  extracted.names.forEach(name => toolNames.add(name));
412
293
  }
413
294
  }
@@ -425,7 +306,7 @@ function extractToolNamesFromFile(
425
306
  if (attr.initializer && ts.isJsxExpression(attr.initializer)) {
426
307
  const expr = attr.initializer.expression;
427
308
  if (expr) {
428
- const extracted = extractToolNamesFromExpression(expr, sourceFile, variableMap, program);
309
+ const extracted = extractToolNamesFromExpression(expr, sourceFile, variableMap);
429
310
  allToolOrder.push(...extracted.order);
430
311
  }
431
312
  }
@@ -459,8 +340,7 @@ function extractToolNamesFromFile(
459
340
  const extracted = extractToolNamesFromExpression(
460
341
  prop.initializer,
461
342
  sourceFile,
462
- variableMap,
463
- program
343
+ variableMap
464
344
  );
465
345
  extracted.names.forEach(name => toolNames.add(name));
466
346
  }
@@ -482,8 +362,7 @@ function extractToolNamesFromFile(
482
362
  const extracted = extractToolNamesFromExpression(
483
363
  prop.initializer,
484
364
  sourceFile,
485
- variableMap,
486
- program
365
+ variableMap
487
366
  );
488
367
  allToolOrder.push(...extracted.order);
489
368
  }
@@ -559,31 +438,30 @@ function findFunctionDefinition(
559
438
  return { sourceFile, node: foundNode };
560
439
  }
561
440
 
562
- // If not found, check imports
563
- const imports: { name: string; from: string; isNamespace?: boolean }[] = [];
441
+ // If not found, check imports (both named and namespace imports)
442
+ const imports: { name: string; from: string; isNamespace: boolean }[] = [];
564
443
 
565
444
  function visitForImports(node: ts.Node) {
566
445
  if (ts.isImportDeclaration(node)) {
567
446
  const importClause = node.importClause;
568
- const modulePath = (node.moduleSpecifier as ts.StringLiteral).text;
569
-
570
447
  if (importClause) {
571
448
  const namedBindings = importClause.namedBindings;
572
-
573
- // Handle namespace imports: import * as tools from "./tools"
574
- if (namedBindings && ts.isNamespaceImport(namedBindings)) {
575
- const namespaceName = namedBindings.name.getText(sourceFile);
576
- // Check if functionName matches the namespace (e.g., "tools" in tools.getLocation)
577
- // We'll handle property access separately
578
- imports.push({ name: namespaceName, from: modulePath, isNamespace: true });
579
- }
580
- // Handle named imports: import { getLocation } from "./tools"
581
- else if (namedBindings && ts.isNamedImports(namedBindings)) {
582
- for (const element of namedBindings.elements) {
583
- const importedName = element.name.getText(sourceFile);
584
- if (importedName === functionName) {
585
- imports.push({ name: importedName, from: modulePath });
449
+ if (namedBindings) {
450
+ if (ts.isNamedImports(namedBindings)) {
451
+ // Named imports: import { getLocation, resetPassword } from './tools'
452
+ for (const element of namedBindings.elements) {
453
+ const importedName = element.name.getText(sourceFile);
454
+ if (importedName === functionName) {
455
+ const modulePath = (node.moduleSpecifier as ts.StringLiteral).text;
456
+ imports.push({ name: importedName, from: modulePath, isNamespace: false });
457
+ }
586
458
  }
459
+ } else if (ts.isNamespaceImport(namedBindings)) {
460
+ // Namespace import: import * as tools from './tools'
461
+ // When we have tools.getLocation, we need to search in the imported module
462
+ const namespaceName = namedBindings.name.getText(sourceFile);
463
+ const modulePath = (node.moduleSpecifier as ts.StringLiteral).text;
464
+ imports.push({ name: namespaceName, from: modulePath, isNamespace: true });
587
465
  }
588
466
  }
589
467
  }
@@ -599,16 +477,16 @@ function findFunctionDefinition(
599
477
  if (resolvedPath) {
600
478
  const importedSourceFile = program.getSourceFile(resolvedPath);
601
479
  if (importedSourceFile) {
602
- // For namespace imports, search for the function name in the imported module
603
480
  if (imp.isNamespace) {
604
- // The functionName should be found directly in the imported module
481
+ // For namespace imports, search for the function name directly in the module
482
+ // (e.g., tools.getLocation -> search for "getLocation" in the tools module)
605
483
  const result = findFunctionDefinition(functionName, importedSourceFile, program);
606
484
  if (result) {
607
485
  return result;
608
486
  }
609
487
  } else {
610
- // For named imports, the name matches
611
- const result = findFunctionDefinition(functionName, importedSourceFile, program);
488
+ // For named imports, the imported name matches the function name
489
+ const result = findFunctionDefinition(imp.name, importedSourceFile, program);
612
490
  if (result) {
613
491
  return result;
614
492
  }
@@ -1497,11 +1375,10 @@ async function extractFunctionMetadata(
1497
1375
  * Main function
1498
1376
  */
1499
1377
  async function autoDiscoverAndExtract(projectRoot: string, outputPath: string) {
1500
- console.log(`\n🔍 Discovering tools in your project...\n`);
1378
+ console.log(`\n🔍 Auto-discovering tools in: ${projectRoot}\n`);
1501
1379
 
1502
1380
  // Find all TypeScript files
1503
1381
  const files = await findToolUsageFiles(projectRoot);
1504
- console.log(`📂 Scanning ${files.length} TypeScript file${files.length !== 1 ? 's' : ''}...`);
1505
1382
 
1506
1383
  // Read tsconfig
1507
1384
  const configPath = ts.findConfigFile(projectRoot, ts.sys.fileExists, 'tsconfig.json');
@@ -1536,34 +1413,19 @@ async function autoDiscoverAndExtract(projectRoot: string, outputPath: string) {
1536
1413
  }
1537
1414
  }
1538
1415
 
1539
- if (allToolUsages.length === 0) {
1540
- console.log(`\n⚠️ No tool usages found in ArctenAgent or useAgent components`);
1541
- console.log(`\n💡 Make sure you're using tools like this:`);
1542
- console.log(` <ArctenAgent safeTools={[getLocation, resetPassword]} />`);
1543
- console.log(` or`);
1544
- console.log(` useAgent({ safeTools: [getLocation, resetPassword] })\n`);
1545
- return;
1546
- }
1547
-
1548
- console.log(`\n✨ Found ${allToolUsages.length} usage site${allToolUsages.length !== 1 ? 's' : ''} with ${allToolNames.size} unique tool${allToolNames.size !== 1 ? 's' : ''}:`);
1549
- allToolUsages.forEach((usage, idx) => {
1550
- const relativePath = path.relative(projectRoot, usage.file);
1551
- const tools = Array.from(usage.toolNames);
1552
- console.log(`\n ${idx + 1}. ${usage.component} in ${relativePath}`);
1553
- console.log(` Tools: ${tools.map(t => `\x1b[36m${t}\x1b[0m`).join(', ')}`);
1416
+ console.log(`✓ Found ${allToolUsages.length} usage site(s) with ${allToolNames.size} unique tool(s)`);
1417
+ allToolUsages.forEach(usage => {
1418
+ console.log(` - ${usage.component} in ${path.relative(projectRoot, usage.file)}`);
1419
+ console.log(` Tools: ${Array.from(usage.toolNames).join(', ')}`);
1554
1420
  });
1555
1421
 
1556
1422
  // Extract metadata for discovered tools
1557
- console.log(`\n📝 Extracting type metadata...\n`);
1423
+ console.log(`\n📝 Extracting types for discovered tools...\n`);
1558
1424
 
1559
1425
  const functionsMap: Record<string, FunctionMetadata> = {};
1560
1426
  const discoveredFrom: string[] = [];
1561
1427
 
1562
- const toolNamesArray = Array.from(allToolNames);
1563
- let successCount = 0;
1564
- let warningCount = 0;
1565
-
1566
- for (const toolName of toolNamesArray) {
1428
+ for (const toolName of allToolNames) {
1567
1429
  let found = false;
1568
1430
 
1569
1431
  // Search in all files for the definition
@@ -1576,10 +1438,8 @@ async function autoDiscoverAndExtract(projectRoot: string, outputPath: string) {
1576
1438
  if (metadata) {
1577
1439
  functionsMap[toolName] = metadata;
1578
1440
  discoveredFrom.push(path.relative(projectRoot, result.sourceFile.fileName));
1579
- const relativePath = path.relative(projectRoot, result.sourceFile.fileName);
1580
- console.log(` ✓ \x1b[32m${toolName}\x1b[0m \x1b[90m(${relativePath})\x1b[0m`);
1441
+ console.log(` ✓ ${toolName} (from ${path.relative(projectRoot, result.sourceFile.fileName)})`);
1581
1442
  found = true;
1582
- successCount++;
1583
1443
  break;
1584
1444
  }
1585
1445
  }
@@ -1587,8 +1447,7 @@ async function autoDiscoverAndExtract(projectRoot: string, outputPath: string) {
1587
1447
  }
1588
1448
 
1589
1449
  if (!found) {
1590
- console.log(` \x1b[33m${toolName}\x1b[0m \x1b[90m(definition not found)\x1b[0m`);
1591
- warningCount++;
1450
+ console.log(` ⚠ ${toolName} (definition not found)`);
1592
1451
  }
1593
1452
  }
1594
1453
 
@@ -1639,24 +1498,11 @@ export const toolMetadata = ${JSON.stringify(output, null, 2)} as const;
1639
1498
  `;
1640
1499
 
1641
1500
  fs.writeFileSync(outputPath, tsContent);
1642
-
1643
- const relativeOutput = path.relative(projectRoot, outputPath);
1644
-
1645
- console.log(`\n${'='.repeat(60)}`);
1646
- if (successCount > 0) {
1647
- console.log(`✅ Successfully extracted ${successCount} tool${successCount !== 1 ? 's' : ''}`);
1648
- }
1649
- if (warningCount > 0) {
1650
- console.log(`⚠️ ${warningCount} tool${warningCount !== 1 ? 's' : ''} not found (check function names)`);
1651
- }
1652
- console.log(`📁 Output: \x1b[36m${relativeOutput}\x1b[0m`);
1653
- console.log(`${'='.repeat(60)}\n`);
1654
-
1655
- if (successCount > 0) {
1656
- console.log(`💡 Usage in your component:`);
1657
- console.log(` import { toolMetadata } from './.arcten/tool-metadata';`);
1658
- console.log(` useAgent({ tools: [...], toolMetadata: toolMetadata.functions })\n`);
1659
- }
1501
+ console.log(`\n✅ Generated metadata for ${Object.keys(functionsMap).length} tool(s)`);
1502
+ console.log(`📁 Output: ${outputPath}`);
1503
+ console.log(`\n💡 Usage in your component:`);
1504
+ console.log(` import { toolMetadata } from './.arcten/tool-metadata';`);
1505
+ console.log(` useAgent({ tools: [...], toolMetadata: toolMetadata.functions })\n`);
1660
1506
  }
1661
1507
 
1662
1508
  // CLI
@@ -1,93 +0,0 @@
1
- #!/usr/bin/env node
2
- /**
3
- * Wrapper script to run the TypeScript CLI
4
- * Works with Node.js - no bun required!
5
- */
6
-
7
- import { spawn } from 'child_process';
8
- import { fileURLToPath } from 'url';
9
- import { dirname, resolve } from 'path';
10
- import { existsSync } from 'fs';
11
-
12
- const __filename = fileURLToPath(import.meta.url);
13
- const __dirname = dirname(__filename);
14
-
15
- // Path to the TypeScript script - resolve relative to this wrapper
16
- const tsScript = resolve(__dirname, 'cli-extract-types-auto.ts');
17
-
18
- // Check if a command is available
19
- function checkCommand(cmd) {
20
- return new Promise((resolve) => {
21
- const check = spawn(cmd, ['--version'], { stdio: 'ignore', shell: true });
22
- check.on('close', (code) => {
23
- resolve(code === 0);
24
- });
25
- check.on('error', () => {
26
- resolve(false);
27
- });
28
- });
29
- }
30
-
31
- async function main() {
32
- if (!existsSync(tsScript)) {
33
- console.error(`❌ Error: Script not found at ${tsScript}`);
34
- process.exit(1);
35
- }
36
-
37
- const args = process.argv.slice(2);
38
-
39
- // Check for bun first (faster and preferred if available)
40
- const hasBun = await checkCommand('bun');
41
-
42
- if (hasBun) {
43
- // Use bun directly - it's faster and can run TypeScript natively
44
- const bunProcess = spawn('bun', [tsScript, ...args], {
45
- stdio: 'inherit',
46
- shell: true
47
- });
48
-
49
- bunProcess.on('close', (code) => {
50
- process.exit(code || 0);
51
- });
52
-
53
- bunProcess.on('error', (err) => {
54
- // If bun fails, try tsx as fallback
55
- tryTsxFallback(args);
56
- });
57
- } else {
58
- // Fallback to tsx via npx if bun isn't available
59
- tryTsxFallback(args);
60
- }
61
- }
62
-
63
- async function tryTsxFallback(args) {
64
- const hasNpx = await checkCommand('npx');
65
-
66
- if (hasNpx) {
67
- // Use tsx via npx - it's lightweight and works great with Node.js
68
- const tsxProcess = spawn('npx', ['-y', 'tsx', tsScript, ...args], {
69
- stdio: 'inherit',
70
- shell: true
71
- });
72
-
73
- tsxProcess.on('close', (code) => {
74
- process.exit(code || 0);
75
- });
76
-
77
- tsxProcess.on('error', (err) => {
78
- console.error('❌ Error: Could not run script');
79
- console.error('Please ensure you have Node.js (with npx) or bun installed');
80
- process.exit(1);
81
- });
82
- } else {
83
- console.error('❌ Error: Could not find a TypeScript runner');
84
- console.error('');
85
- console.error('Please install one of the following:');
86
- console.error(' - bun: curl -fsSL https://bun.sh/install | bash (recommended)');
87
- console.error(' - Node.js (comes with npx)');
88
- process.exit(1);
89
- }
90
- }
91
-
92
- main();
93
-
@@ -1,157 +0,0 @@
1
- #!/usr/bin/env node
2
- /**
3
- * Postinstall script to check and optionally update @arcteninc/core version
4
- * This helps users stay on the latest version without manually updating package.json
5
- */
6
-
7
- const fs = require('fs');
8
- const path = require('path');
9
- const { execSync } = require('child_process');
10
-
11
- function findPackageJson(startPath = process.cwd()) {
12
- let currentPath = startPath;
13
-
14
- // Start from current directory and walk up to find package.json
15
- // Skip node_modules directories
16
- while (currentPath !== path.dirname(currentPath)) {
17
- // Skip if we're in a node_modules directory
18
- if (currentPath.includes('node_modules')) {
19
- currentPath = path.dirname(currentPath);
20
- continue;
21
- }
22
-
23
- const packageJsonPath = path.join(currentPath, 'package.json');
24
- if (fs.existsSync(packageJsonPath)) {
25
- // Make sure this isn't @arcteninc/core's own package.json
26
- try {
27
- const pkg = JSON.parse(fs.readFileSync(packageJsonPath, 'utf-8'));
28
- if (pkg.name === '@arcteninc/core') {
29
- // This is the core package itself, go up one level
30
- currentPath = path.dirname(currentPath);
31
- continue;
32
- }
33
- } catch (e) {
34
- // Invalid JSON, skip
35
- currentPath = path.dirname(currentPath);
36
- continue;
37
- }
38
-
39
- return packageJsonPath;
40
- }
41
- currentPath = path.dirname(currentPath);
42
- }
43
-
44
- return null;
45
- }
46
-
47
- function getLatestVersion() {
48
- try {
49
- const output = execSync('npm view @arcteninc/core version', { encoding: 'utf-8', stdio: 'pipe' });
50
- return output.trim();
51
- } catch (error) {
52
- console.warn('⚠️ Could not check latest version:', error.message);
53
- return null;
54
- }
55
- }
56
-
57
- function getInstalledVersion() {
58
- try {
59
- const packageJsonPath = findPackageJson();
60
- if (!packageJsonPath) {
61
- return null;
62
- }
63
-
64
- const packageJson = JSON.parse(fs.readFileSync(packageJsonPath, 'utf-8'));
65
- const deps = { ...packageJson.dependencies, ...packageJson.devDependencies };
66
- const version = deps['@arcteninc/core'];
67
-
68
- return version ? { version, packageJsonPath, packageJson } : null;
69
- } catch (error) {
70
- return null;
71
- }
72
- }
73
-
74
- // Removed auto-update function - users should update manually
75
-
76
- function main() {
77
- // Find the user's project root (not node_modules/@arcteninc/core)
78
- // Walk up from current directory to find package.json that uses @arcteninc/core
79
- let projectRoot = process.cwd();
80
-
81
- // If we're in node_modules/@arcteninc/core, go up to project root
82
- if (projectRoot.includes('node_modules')) {
83
- // Find the project root by looking for package.json that's not @arcteninc/core
84
- const parts = projectRoot.split(path.sep);
85
- const nodeModulesIndex = parts.indexOf('node_modules');
86
- if (nodeModulesIndex !== -1) {
87
- projectRoot = parts.slice(0, nodeModulesIndex).join(path.sep);
88
- }
89
- }
90
-
91
- // Change to project root to find package.json
92
- const originalCwd = process.cwd();
93
- try {
94
- process.chdir(projectRoot);
95
- } catch (e) {
96
- // Can't change directory, use original
97
- }
98
-
99
- // Only run if we're in a project that uses @arcteninc/core
100
- const installed = getInstalledVersion();
101
- if (!installed) {
102
- process.chdir(originalCwd);
103
- return; // Not installed, nothing to do
104
- }
105
-
106
- const latestVersion = getLatestVersion();
107
- if (!latestVersion) {
108
- try {
109
- process.chdir(originalCwd);
110
- } catch (e) {
111
- // Ignore
112
- }
113
- return; // Couldn't check, skip
114
- }
115
-
116
- // Extract current version number (remove ^, ~, etc.)
117
- const currentVersionMatch = installed.version.match(/(\d+\.\d+\.\d+)/);
118
- if (!currentVersionMatch) {
119
- try {
120
- process.chdir(originalCwd);
121
- } catch (e) {
122
- // Ignore
123
- }
124
- return; // Invalid version format
125
- }
126
-
127
- const currentVersion = currentVersionMatch[1];
128
-
129
- if (currentVersion !== latestVersion) {
130
- console.log(`\n📦 @arcteninc/core update available:`);
131
- console.log(` Current: ${currentVersion}`);
132
- console.log(` Latest: ${latestVersion}`);
133
-
134
- if (installed.version.startsWith('^') || installed.version.startsWith('~')) {
135
- console.log(` Run 'npm update @arcteninc/core' to update within your version range`);
136
- } else {
137
- console.log(` Consider updating to '^${latestVersion}' in package.json`);
138
- console.log(` Then run 'npm install' to get the latest version`);
139
- }
140
- console.log(` Or use: \x1b[36mnpx arcten update\x1b[0m`);
141
- }
142
-
143
- // Restore original directory
144
- try {
145
- process.chdir(originalCwd);
146
- } catch (e) {
147
- // Ignore
148
- }
149
- }
150
-
151
- // Only run if called directly (not when required)
152
- if (require.main === module) {
153
- main();
154
- }
155
-
156
- module.exports = { main, getLatestVersion, getInstalledVersion, findPackageJson };
157
-
@@ -1,125 +0,0 @@
1
- #!/usr/bin/env node
2
- /**
3
- * Manual update command for @arcteninc/core
4
- * Usage: arcten update
5
- *
6
- * This allows users to explicitly update their package.json
7
- */
8
-
9
- const fs = require('fs');
10
- const path = require('path');
11
- const { execSync } = require('child_process');
12
- const { findPackageJson } = require('./postinstall-check-version.cjs');
13
-
14
- function findPackageJsonLocal(startPath = process.cwd()) {
15
- let currentPath = startPath;
16
-
17
- while (currentPath !== path.dirname(currentPath)) {
18
- if (currentPath.includes('node_modules')) {
19
- currentPath = path.dirname(currentPath);
20
- continue;
21
- }
22
-
23
- const packageJsonPath = path.join(currentPath, 'package.json');
24
- if (fs.existsSync(packageJsonPath)) {
25
- try {
26
- const pkg = JSON.parse(fs.readFileSync(packageJsonPath, 'utf-8'));
27
- if (pkg.name === '@arcteninc/core') {
28
- currentPath = path.dirname(currentPath);
29
- continue;
30
- }
31
- } catch (e) {
32
- currentPath = path.dirname(currentPath);
33
- continue;
34
- }
35
-
36
- return packageJsonPath;
37
- }
38
- currentPath = path.dirname(currentPath);
39
- }
40
-
41
- return null;
42
- }
43
-
44
- function getLatestVersion() {
45
- try {
46
- const output = execSync('npm view @arcteninc/core version', { encoding: 'utf-8', stdio: 'pipe' });
47
- return output.trim();
48
- } catch (error) {
49
- console.error('❌ Could not check latest version:', error.message);
50
- return null;
51
- }
52
- }
53
-
54
- function updateVersion(packageJsonPath, packageJson, latestVersion) {
55
- let updated = false;
56
-
57
- if (packageJson.dependencies && packageJson.dependencies['@arcteninc/core']) {
58
- packageJson.dependencies['@arcteninc/core'] = `^${latestVersion}`;
59
- updated = true;
60
- }
61
- if (packageJson.devDependencies && packageJson.devDependencies['@arcteninc/core']) {
62
- packageJson.devDependencies['@arcteninc/core'] = `^${latestVersion}`;
63
- updated = true;
64
- }
65
-
66
- if (updated) {
67
- fs.writeFileSync(packageJsonPath, JSON.stringify(packageJson, null, 2) + '\n');
68
- console.log(`✅ Updated to \x1b[32m^${latestVersion}\x1b[0m in package.json\n`);
69
- return true;
70
- }
71
-
72
- return false;
73
- }
74
-
75
- function main() {
76
- const packageJsonPath = findPackageJson();
77
- if (!packageJsonPath) {
78
- console.error('❌ Could not find package.json');
79
- process.exit(1);
80
- }
81
-
82
- const packageJson = JSON.parse(fs.readFileSync(packageJsonPath, 'utf-8'));
83
- const deps = { ...packageJson.dependencies, ...packageJson.devDependencies };
84
- const currentVersion = deps['@arcteninc/core'];
85
-
86
- if (!currentVersion) {
87
- console.error('❌ @arcteninc/core not found in dependencies');
88
- process.exit(1);
89
- }
90
-
91
- const latestVersion = getLatestVersion();
92
- if (!latestVersion) {
93
- process.exit(1);
94
- }
95
-
96
- const currentVersionMatch = currentVersion.match(/(\d+\.\d+\.\d+)/);
97
- if (!currentVersionMatch) {
98
- console.error('❌ Invalid version format:', currentVersion);
99
- process.exit(1);
100
- }
101
-
102
- const current = currentVersionMatch[1];
103
-
104
- if (current === latestVersion) {
105
- console.log(`\n✅ Already on latest version: \x1b[32m${latestVersion}\x1b[0m\n`);
106
- return;
107
- }
108
-
109
- console.log(`\n📦 Updating @arcteninc/core\n`);
110
- console.log(` Current: \x1b[33m${current}\x1b[0m`);
111
- console.log(` Latest: \x1b[32m${latestVersion}\x1b[0m\n`);
112
-
113
- if (updateVersion(packageJsonPath, packageJson, latestVersion)) {
114
- console.log(`💡 Next steps:`);
115
- console.log(` 1. Review the changes in package.json`);
116
- console.log(` 2. Run \x1b[36mnpm install\x1b[0m to install the update\n`);
117
- }
118
- }
119
-
120
- if (require.main === module) {
121
- main();
122
- }
123
-
124
- module.exports = { main };
125
-