@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 +7 -8
- package/scripts/arcten-cli.cjs +31 -31
- package/scripts/cli-extract-types-auto-wrapper.js +108 -0
- package/scripts/cli-extract-types-auto.ts +71 -225
- package/scripts/cli-extract-types-auto.js +0 -93
- package/scripts/postinstall-check-version.cjs +0 -157
- package/scripts/update-core.cjs +0 -125
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@arcteninc/core",
|
|
3
|
-
"version": "0.0.
|
|
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",
|
package/scripts/arcten-cli.cjs
CHANGED
|
@@ -14,9 +14,10 @@ const path = require('path');
|
|
|
14
14
|
const fs = require('fs');
|
|
15
15
|
|
|
16
16
|
const commands = {
|
|
17
|
-
'extract-types':
|
|
18
|
-
'tools':
|
|
19
|
-
'
|
|
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
|
-
|
|
33
|
+
extract-types, tools, setup Extract tool metadata from your project
|
|
34
|
+
Aliases: arcten tools, arcten setup
|
|
34
35
|
|
|
35
|
-
update
|
|
36
|
-
|
|
36
|
+
update Update @arcteninc/core to latest version
|
|
37
|
+
Updates package.json and shows next steps
|
|
37
38
|
|
|
38
|
-
help
|
|
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
|
|
43
|
-
arcten
|
|
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
|
-
|
|
70
|
-
|
|
71
|
-
//
|
|
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 (
|
|
76
|
-
scriptPath = path.join(__dirname, 'update-core.
|
|
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
|
-
|
|
79
|
-
|
|
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
|
|
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
|
-
|
|
119
|
-
|
|
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
|
|
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
|
-
|
|
139
|
-
|
|
140
|
-
|
|
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
|
-
|
|
156
|
-
|
|
157
|
-
|
|
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
|
|
180
|
+
// Property access: wrappedTools.getRAGInfo
|
|
196
181
|
if (ts.isPropertyAccessExpression(node)) {
|
|
197
182
|
const propName = node.name.text;
|
|
198
|
-
|
|
199
|
-
|
|
200
|
-
|
|
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
|
|
218
|
-
|
|
219
|
-
|
|
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
|
|
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
|
|
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
|
|
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
|
-
|
|
574
|
-
|
|
575
|
-
|
|
576
|
-
|
|
577
|
-
|
|
578
|
-
|
|
579
|
-
|
|
580
|
-
|
|
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
|
-
//
|
|
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(
|
|
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🔍
|
|
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
|
-
|
|
1540
|
-
|
|
1541
|
-
console.log(
|
|
1542
|
-
console.log(`
|
|
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
|
|
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
|
|
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
|
-
|
|
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(`
|
|
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
|
-
|
|
1644
|
-
|
|
1645
|
-
console.log(
|
|
1646
|
-
|
|
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
|
-
|
package/scripts/update-core.cjs
DELETED
|
@@ -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
|
-
|