@agentforge-ai/cli 0.6.0 → 0.7.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@agentforge-ai/cli",
3
- "version": "0.6.0",
3
+ "version": "0.7.1",
4
4
  "description": "CLI tool for creating, running, and managing AgentForge projects",
5
5
  "type": "module",
6
6
  "bin": {
@@ -19,7 +19,8 @@
19
19
  "fs-extra": "^11.2.0",
20
20
  "gray-matter": "^4.0.3",
21
21
  "ora": "^8.0.0",
22
- "prompts": "^2.4.2"
22
+ "prompts": "^2.4.2",
23
+ "@agentforge-ai/core": "0.7.1"
23
24
  },
24
25
  "devDependencies": {
25
26
  "@types/fs-extra": "^11.0.4",
@@ -38,7 +38,7 @@ export const webSearch = createTool({
38
38
  {
39
39
  name: 'code-executor',
40
40
  displayName: 'Code Executor',
41
- description: 'Safely execute JavaScript/TypeScript code snippets in a sandboxed environment and return the output.',
41
+ description: 'Execute JavaScript/TypeScript code snippets via the AgentForge sandbox API and return the output.',
42
42
  category: 'Tools',
43
43
  version: '1.0.0',
44
44
  author: 'AgentForge',
@@ -48,18 +48,25 @@ import { z } from 'zod';
48
48
 
49
49
  export const codeExecutor = createTool({
50
50
  id: 'code-executor',
51
- description: 'Execute JavaScript code and return the result',
51
+ description: 'Execute JavaScript code via the sandbox API and return the result',
52
52
  inputSchema: z.object({
53
53
  code: z.string().describe('JavaScript code to execute'),
54
+ language: z.enum(['javascript', 'typescript']).default('javascript'),
54
55
  }),
55
56
  execute: async ({ context }) => {
56
- try {
57
- const fn = new Function('return (async () => {' + context.code + '})()');
58
- const result = await fn();
59
- return { success: true, output: String(result) };
60
- } catch (error: any) {
61
- return { success: false, error: error.message };
57
+ // Code is executed server-side via the AgentForge sandbox API,
58
+ // not via eval or Function constructor, to prevent arbitrary code execution risks.
59
+ const response = await fetch('/api/sandbox/execute', {
60
+ method: 'POST',
61
+ headers: { 'Content-Type': 'application/json' },
62
+ body: JSON.stringify({ code: context.code, language: context.language }),
63
+ });
64
+ if (!response.ok) {
65
+ const err = await response.json().catch(() => ({ error: 'Unknown error' }));
66
+ return { success: false, error: err.error ?? 'Sandbox execution failed' };
62
67
  }
68
+ const data = await response.json();
69
+ return { success: true, output: String(data.output ?? '') };
63
70
  },
64
71
  });`,
65
72
  },
@@ -74,16 +81,71 @@ export const codeExecutor = createTool({
74
81
  code: `import { createTool } from '@mastra/core';
75
82
  import { z } from 'zod';
76
83
 
84
+ // Safe arithmetic evaluator — no eval or Function constructor used.
85
+ function evaluateExpression(expr: string): number {
86
+ // Allow only digits, operators, parentheses, dots, and whitespace.
87
+ if (!/^[0-9+\\-*/().%\\s]+$/.test(expr)) {
88
+ throw new Error('Expression contains invalid characters');
89
+ }
90
+ // Recursive descent parser for: expr = term (('+' | '-') term)*
91
+ let pos = 0;
92
+ const peek = () => expr[pos] ?? '';
93
+ const consume = () => expr[pos++];
94
+ const skipWs = () => { while (peek() === ' ') consume(); };
95
+
96
+ function parseNumber(): number {
97
+ skipWs();
98
+ let num = '';
99
+ if (peek() === '(') { consume(); const v = parseExpr(); skipWs(); consume(); return v; }
100
+ while (/[0-9.]/.test(peek())) num += consume();
101
+ if (num === '') throw new Error('Expected number');
102
+ return parseFloat(num);
103
+ }
104
+
105
+ function parseFactor(): number {
106
+ skipWs();
107
+ if (peek() === '-') { consume(); return -parseFactor(); }
108
+ return parseNumber();
109
+ }
110
+
111
+ function parseTerm(): number {
112
+ let left = parseFactor();
113
+ skipWs();
114
+ while (peek() === '*' || peek() === '/') {
115
+ const op = consume(); skipWs();
116
+ const right = parseFactor();
117
+ left = op === '*' ? left * right : left / right;
118
+ skipWs();
119
+ }
120
+ return left;
121
+ }
122
+
123
+ function parseExpr(): number {
124
+ let left = parseTerm();
125
+ skipWs();
126
+ while (peek() === '+' || peek() === '-') {
127
+ const op = consume(); skipWs();
128
+ const right = parseTerm();
129
+ left = op === '+' ? left + right : left - right;
130
+ skipWs();
131
+ }
132
+ return left;
133
+ }
134
+
135
+ const result = parseExpr();
136
+ if (pos !== expr.length) throw new Error('Unexpected token at position ' + pos);
137
+ return result;
138
+ }
139
+
77
140
  export const calculator = createTool({
78
141
  id: 'calculator',
79
- description: 'Evaluate a mathematical expression',
142
+ description: 'Evaluate a mathematical expression safely',
80
143
  inputSchema: z.object({
81
144
  expression: z.string().describe('Math expression to evaluate, e.g. "2 + 2 * 3"'),
82
145
  }),
83
146
  execute: async ({ context }) => {
84
147
  try {
85
- const sanitized = context.expression.replace(/[^0-9+\\-*/().%\\s]/g, '');
86
- const result = Function('"use strict"; return (' + sanitized + ')')();
148
+ const result = evaluateExpression(context.expression.trim());
87
149
  return { result: Number(result), expression: context.expression };
88
150
  } catch (error: any) {
89
151
  return { error: 'Invalid expression: ' + error.message };