@arcteninc/core 0.0.62 → 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.62",
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
@@ -129,12 +129,9 @@ function extractToolNamesFromExpression(
129
129
  // Property access: tools.getOrders -> extract "getOrders"
130
130
  const propName = element.name.text;
131
131
  if (propName) {
132
- // Try to resolve the module to find the actual function name
133
- const resolvedName = resolvePropertyAccess(element, sourceFile, program);
134
- const finalName = resolvedName || propName;
135
- if (!toolNames.has(finalName)) {
136
- toolNames.add(finalName);
137
- toolOrder.push(finalName); // Preserve order
132
+ if (!toolNames.has(propName)) {
133
+ toolNames.add(propName);
134
+ toolOrder.push(propName); // Preserve order
138
135
  }
139
136
  }
140
137
  } else if (ts.isElementAccessExpression(element)) {
@@ -143,12 +140,9 @@ function extractToolNamesFromExpression(
143
140
  if (ts.isStringLiteral(indexExpr) || ts.isNumericLiteral(indexExpr)) {
144
141
  const name = indexExpr.text;
145
142
  if (name && name !== 'undefined' && name !== 'null') {
146
- // Try to resolve the module
147
- const resolvedName = resolveElementAccess(element, sourceFile, program);
148
- const finalName = resolvedName || name;
149
- if (!toolNames.has(finalName)) {
150
- toolNames.add(finalName);
151
- toolOrder.push(finalName); // Preserve order
143
+ if (!toolNames.has(name)) {
144
+ toolNames.add(name);
145
+ toolOrder.push(name); // Preserve order
152
146
  }
153
147
  }
154
148
  } else {
@@ -183,15 +177,12 @@ function extractToolNamesFromExpression(
183
177
  return;
184
178
  }
185
179
 
186
- // Property access: wrappedTools.getRAGInfo or tools.getLocation
180
+ // Property access: wrappedTools.getRAGInfo
187
181
  if (ts.isPropertyAccessExpression(node)) {
188
182
  const propName = node.name.text;
189
- // Try to resolve the module to find the actual function name
190
- const resolvedName = resolvePropertyAccess(node, sourceFile, program);
191
- const finalName = resolvedName || propName;
192
- if (!toolNames.has(finalName)) {
193
- toolNames.add(finalName);
194
- toolOrder.push(finalName);
183
+ if (!toolNames.has(propName)) {
184
+ toolNames.add(propName);
185
+ toolOrder.push(propName);
195
186
  }
196
187
  return;
197
188
  }
@@ -201,20 +192,26 @@ function extractToolNamesFromExpression(
201
192
  const callExpr = node.expression;
202
193
  if (ts.isIdentifier(callExpr)) {
203
194
  const funcName = callExpr.text;
204
- if (funcName === 'useMemo') {
205
- const memoizedExpr = extractToolsFromUseMemo(node, sourceFile, variableMap);
206
- if (memoizedExpr) {
207
- 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
208
214
  }
209
- }
210
- }
211
- // Also handle other function calls that might return arrays
212
- // For example: someFunction() that returns an array of tools
213
- if (node.arguments.length === 0) {
214
- // Check if this call might be a variable reference
215
- const varExpr = variableMap.get(callExpr.getText(sourceFile));
216
- if (varExpr) {
217
- extractFromExpr(varExpr);
218
215
  }
219
216
  }
220
217
  return;
@@ -231,60 +228,8 @@ function extractToolNamesFromExpression(
231
228
  return { names: toolNames, order: toolOrder };
232
229
  }
233
230
 
234
- /**
235
- * Resolve property access like tools.getLocation to find the actual function name
236
- * Returns the resolved name if found, or null if couldn't resolve
237
- */
238
- function resolvePropertyAccess(
239
- expr: ts.PropertyAccessExpression,
240
- sourceFile: ts.SourceFile,
241
- program?: ts.Program
242
- ): string | null {
243
- if (!program) return null;
244
-
245
- const checker = program.getTypeChecker();
246
- const symbol = checker.getSymbolAtLocation(expr);
247
-
248
- if (symbol) {
249
- // Get the name of the property (e.g., "getLocation")
250
- return symbol.getName();
251
- }
252
-
253
- // Fallback: try to resolve the object (e.g., "tools")
254
- const objectExpr = expr.expression;
255
- if (ts.isIdentifier(objectExpr)) {
256
- const objectName = objectExpr.text;
257
- // Check if this is an imported module (e.g., import * as tools from "./tools")
258
- // We'll handle this in the import resolution
259
- return null;
260
- }
261
-
262
- return null;
263
- }
264
-
265
- /**
266
- * Resolve element access like tools['getLocation'] to find the actual function name
267
- */
268
- function resolveElementAccess(
269
- expr: ts.ElementAccessExpression,
270
- sourceFile: ts.SourceFile,
271
- program?: ts.Program
272
- ): string | null {
273
- if (!program) return null;
274
-
275
- const checker = program.getTypeChecker();
276
- const symbol = checker.getSymbolAtLocation(expr);
277
-
278
- if (symbol) {
279
- return symbol.getName();
280
- }
281
-
282
- return null;
283
- }
284
-
285
231
  /**
286
232
  * Build a map of variable declarations in the file
287
- * Handles: const x = [...], const x = useMemo(...), etc.
288
233
  */
289
234
  function buildVariableMap(sourceFile: ts.SourceFile): Map<string, ts.Expression> {
290
235
  const variableMap = new Map<string, ts.Expression>();
@@ -313,46 +258,6 @@ function buildVariableMap(sourceFile: ts.SourceFile): Map<string, ts.Expression>
313
258
  return variableMap;
314
259
  }
315
260
 
316
- /**
317
- * Extract tools from useMemo callback, handling both arrow functions and regular functions
318
- */
319
- function extractToolsFromUseMemo(
320
- useMemoCall: ts.CallExpression,
321
- sourceFile: ts.SourceFile,
322
- variableMap: Map<string, ts.Expression>
323
- ): ts.Expression | null {
324
- if (useMemoCall.arguments.length === 0) return null;
325
-
326
- const firstArg = useMemoCall.arguments[0];
327
-
328
- // Arrow function: () => [...]
329
- if (ts.isArrowFunction(firstArg)) {
330
- if (firstArg.body) {
331
- if (ts.isBlock(firstArg.body)) {
332
- // Block body: () => { return [...] }
333
- for (const stmt of firstArg.body.statements) {
334
- if (ts.isReturnStatement(stmt) && stmt.expression) {
335
- return stmt.expression;
336
- }
337
- }
338
- } else {
339
- // Expression body: () => [...]
340
- return firstArg.body;
341
- }
342
- }
343
- }
344
- // Regular function: function() { return [...] }
345
- else if (ts.isFunctionExpression(firstArg) && firstArg.body) {
346
- for (const stmt of firstArg.body.statements) {
347
- if (ts.isReturnStatement(stmt) && stmt.expression) {
348
- return stmt.expression;
349
- }
350
- }
351
- }
352
-
353
- return null;
354
- }
355
-
356
261
  /**
357
262
  * Extract tool names from ArctenAgent or useAgent usage
358
263
  */
@@ -383,7 +288,7 @@ function extractToolNamesFromFile(
383
288
  if (attr.initializer && ts.isJsxExpression(attr.initializer)) {
384
289
  const expr = attr.initializer.expression;
385
290
  if (expr) {
386
- const extracted = extractToolNamesFromExpression(expr, sourceFile, variableMap, program);
291
+ const extracted = extractToolNamesFromExpression(expr, sourceFile, variableMap);
387
292
  extracted.names.forEach(name => toolNames.add(name));
388
293
  }
389
294
  }
@@ -401,7 +306,7 @@ function extractToolNamesFromFile(
401
306
  if (attr.initializer && ts.isJsxExpression(attr.initializer)) {
402
307
  const expr = attr.initializer.expression;
403
308
  if (expr) {
404
- const extracted = extractToolNamesFromExpression(expr, sourceFile, variableMap, program);
309
+ const extracted = extractToolNamesFromExpression(expr, sourceFile, variableMap);
405
310
  allToolOrder.push(...extracted.order);
406
311
  }
407
312
  }
@@ -435,8 +340,7 @@ function extractToolNamesFromFile(
435
340
  const extracted = extractToolNamesFromExpression(
436
341
  prop.initializer,
437
342
  sourceFile,
438
- variableMap,
439
- program
343
+ variableMap
440
344
  );
441
345
  extracted.names.forEach(name => toolNames.add(name));
442
346
  }
@@ -458,8 +362,7 @@ function extractToolNamesFromFile(
458
362
  const extracted = extractToolNamesFromExpression(
459
363
  prop.initializer,
460
364
  sourceFile,
461
- variableMap,
462
- program
365
+ variableMap
463
366
  );
464
367
  allToolOrder.push(...extracted.order);
465
368
  }
@@ -535,31 +438,30 @@ function findFunctionDefinition(
535
438
  return { sourceFile, node: foundNode };
536
439
  }
537
440
 
538
- // If not found, check imports
539
- 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 }[] = [];
540
443
 
541
444
  function visitForImports(node: ts.Node) {
542
445
  if (ts.isImportDeclaration(node)) {
543
446
  const importClause = node.importClause;
544
- const modulePath = (node.moduleSpecifier as ts.StringLiteral).text;
545
-
546
447
  if (importClause) {
547
448
  const namedBindings = importClause.namedBindings;
548
-
549
- // Handle namespace imports: import * as tools from "./tools"
550
- if (namedBindings && ts.isNamespaceImport(namedBindings)) {
551
- const namespaceName = namedBindings.name.getText(sourceFile);
552
- // Check if functionName matches the namespace (e.g., "tools" in tools.getLocation)
553
- // We'll handle property access separately
554
- imports.push({ name: namespaceName, from: modulePath, isNamespace: true });
555
- }
556
- // Handle named imports: import { getLocation } from "./tools"
557
- else if (namedBindings && ts.isNamedImports(namedBindings)) {
558
- for (const element of namedBindings.elements) {
559
- const importedName = element.name.getText(sourceFile);
560
- if (importedName === functionName) {
561
- 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
+ }
562
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 });
563
465
  }
564
466
  }
565
467
  }
@@ -575,16 +477,16 @@ function findFunctionDefinition(
575
477
  if (resolvedPath) {
576
478
  const importedSourceFile = program.getSourceFile(resolvedPath);
577
479
  if (importedSourceFile) {
578
- // For namespace imports, search for the function name in the imported module
579
480
  if (imp.isNamespace) {
580
- // 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)
581
483
  const result = findFunctionDefinition(functionName, importedSourceFile, program);
582
484
  if (result) {
583
485
  return result;
584
486
  }
585
487
  } else {
586
- // For named imports, the name matches
587
- 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);
588
490
  if (result) {
589
491
  return result;
590
492
  }
@@ -1473,11 +1375,10 @@ async function extractFunctionMetadata(
1473
1375
  * Main function
1474
1376
  */
1475
1377
  async function autoDiscoverAndExtract(projectRoot: string, outputPath: string) {
1476
- console.log(`\n🔍 Discovering tools in your project...\n`);
1378
+ console.log(`\n🔍 Auto-discovering tools in: ${projectRoot}\n`);
1477
1379
 
1478
1380
  // Find all TypeScript files
1479
1381
  const files = await findToolUsageFiles(projectRoot);
1480
- console.log(`📂 Scanning ${files.length} TypeScript file${files.length !== 1 ? 's' : ''}...`);
1481
1382
 
1482
1383
  // Read tsconfig
1483
1384
  const configPath = ts.findConfigFile(projectRoot, ts.sys.fileExists, 'tsconfig.json');
@@ -1512,34 +1413,19 @@ async function autoDiscoverAndExtract(projectRoot: string, outputPath: string) {
1512
1413
  }
1513
1414
  }
1514
1415
 
1515
- if (allToolUsages.length === 0) {
1516
- console.log(`\n⚠️ No tool usages found in ArctenAgent or useAgent components`);
1517
- console.log(`\n💡 Make sure you're using tools like this:`);
1518
- console.log(` <ArctenAgent safeTools={[getLocation, resetPassword]} />`);
1519
- console.log(` or`);
1520
- console.log(` useAgent({ safeTools: [getLocation, resetPassword] })\n`);
1521
- return;
1522
- }
1523
-
1524
- console.log(`\n✨ Found ${allToolUsages.length} usage site${allToolUsages.length !== 1 ? 's' : ''} with ${allToolNames.size} unique tool${allToolNames.size !== 1 ? 's' : ''}:`);
1525
- allToolUsages.forEach((usage, idx) => {
1526
- const relativePath = path.relative(projectRoot, usage.file);
1527
- const tools = Array.from(usage.toolNames);
1528
- console.log(`\n ${idx + 1}. ${usage.component} in ${relativePath}`);
1529
- 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(', ')}`);
1530
1420
  });
1531
1421
 
1532
1422
  // Extract metadata for discovered tools
1533
- console.log(`\n📝 Extracting type metadata...\n`);
1423
+ console.log(`\n📝 Extracting types for discovered tools...\n`);
1534
1424
 
1535
1425
  const functionsMap: Record<string, FunctionMetadata> = {};
1536
1426
  const discoveredFrom: string[] = [];
1537
1427
 
1538
- const toolNamesArray = Array.from(allToolNames);
1539
- let successCount = 0;
1540
- let warningCount = 0;
1541
-
1542
- for (const toolName of toolNamesArray) {
1428
+ for (const toolName of allToolNames) {
1543
1429
  let found = false;
1544
1430
 
1545
1431
  // Search in all files for the definition
@@ -1552,10 +1438,8 @@ async function autoDiscoverAndExtract(projectRoot: string, outputPath: string) {
1552
1438
  if (metadata) {
1553
1439
  functionsMap[toolName] = metadata;
1554
1440
  discoveredFrom.push(path.relative(projectRoot, result.sourceFile.fileName));
1555
- const relativePath = path.relative(projectRoot, result.sourceFile.fileName);
1556
- console.log(` ✓ \x1b[32m${toolName}\x1b[0m \x1b[90m(${relativePath})\x1b[0m`);
1441
+ console.log(` ✓ ${toolName} (from ${path.relative(projectRoot, result.sourceFile.fileName)})`);
1557
1442
  found = true;
1558
- successCount++;
1559
1443
  break;
1560
1444
  }
1561
1445
  }
@@ -1563,8 +1447,7 @@ async function autoDiscoverAndExtract(projectRoot: string, outputPath: string) {
1563
1447
  }
1564
1448
 
1565
1449
  if (!found) {
1566
- console.log(` \x1b[33m${toolName}\x1b[0m \x1b[90m(definition not found)\x1b[0m`);
1567
- warningCount++;
1450
+ console.log(` ⚠ ${toolName} (definition not found)`);
1568
1451
  }
1569
1452
  }
1570
1453
 
@@ -1615,24 +1498,11 @@ export const toolMetadata = ${JSON.stringify(output, null, 2)} as const;
1615
1498
  `;
1616
1499
 
1617
1500
  fs.writeFileSync(outputPath, tsContent);
1618
-
1619
- const relativeOutput = path.relative(projectRoot, outputPath);
1620
-
1621
- console.log(`\n${'='.repeat(60)}`);
1622
- if (successCount > 0) {
1623
- console.log(`✅ Successfully extracted ${successCount} tool${successCount !== 1 ? 's' : ''}`);
1624
- }
1625
- if (warningCount > 0) {
1626
- console.log(`⚠️ ${warningCount} tool${warningCount !== 1 ? 's' : ''} not found (check function names)`);
1627
- }
1628
- console.log(`📁 Output: \x1b[36m${relativeOutput}\x1b[0m`);
1629
- console.log(`${'='.repeat(60)}\n`);
1630
-
1631
- if (successCount > 0) {
1632
- console.log(`💡 Usage in your component:`);
1633
- console.log(` import { toolMetadata } from './.arcten/tool-metadata';`);
1634
- console.log(` useAgent({ tools: [...], toolMetadata: toolMetadata.functions })\n`);
1635
- }
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`);
1636
1506
  }
1637
1507
 
1638
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
-