@elizaos/plugin-ngrok 2.0.0-beta.1 → 2.0.11-beta.7

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.
Files changed (38) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +38 -294
  3. package/package.json +24 -7
  4. package/src/__tests__/test-utils.ts +2 -2
  5. package/src/__tests__/unit/environment.test.ts +1 -1
  6. package/dist/__tests__/NgrokTestSuite.d.ts +0 -6
  7. package/dist/__tests__/NgrokTestSuite.d.ts.map +0 -1
  8. package/dist/__tests__/NgrokTestSuite.js +0 -92
  9. package/dist/__tests__/NgrokTestSuite.js.map +0 -1
  10. package/dist/actions/get-tunnel-status.d.ts +0 -4
  11. package/dist/actions/get-tunnel-status.d.ts.map +0 -1
  12. package/dist/actions/get-tunnel-status.js +0 -186
  13. package/dist/actions/get-tunnel-status.js.map +0 -1
  14. package/dist/actions/start-tunnel.d.ts +0 -4
  15. package/dist/actions/start-tunnel.d.ts.map +0 -1
  16. package/dist/actions/start-tunnel.js +0 -221
  17. package/dist/actions/start-tunnel.js.map +0 -1
  18. package/dist/actions/stop-tunnel.d.ts +0 -4
  19. package/dist/actions/stop-tunnel.d.ts.map +0 -1
  20. package/dist/actions/stop-tunnel.js +0 -174
  21. package/dist/actions/stop-tunnel.js.map +0 -1
  22. package/dist/environment.d.ts +0 -12
  23. package/dist/environment.d.ts.map +0 -1
  24. package/dist/environment.js +0 -68
  25. package/dist/environment.js.map +0 -1
  26. package/dist/index.d.ts +0 -13
  27. package/dist/index.d.ts.map +0 -1
  28. package/dist/index.js +0 -29
  29. package/dist/index.js.map +0 -1
  30. package/dist/services/NgrokService.d.ts +0 -30
  31. package/dist/services/NgrokService.d.ts.map +0 -1
  32. package/dist/services/NgrokService.js +0 -333
  33. package/dist/services/NgrokService.js.map +0 -1
  34. package/src/__tests__/e2e/real-ngrok.test.ts +0 -543
  35. package/src/__tests__/unit/actions.test.ts +0 -402
  36. package/src/actions/get-tunnel-status.ts +0 -218
  37. package/src/actions/start-tunnel.ts +0 -255
  38. package/src/actions/stop-tunnel.ts +0 -203
@@ -1,255 +0,0 @@
1
- import {
2
- type Action,
3
- type ActionExample,
4
- type ActionResult,
5
- elizaLogger,
6
- type HandlerCallback,
7
- type IAgentRuntime,
8
- type Memory,
9
- ModelType,
10
- type State,
11
- } from '@elizaos/core';
12
- import { getTunnelService } from '@elizaos/plugin-tunnel';
13
-
14
- const startTunnelTemplate = `
15
- Respond with a JSON object containing the port number to start the ngrok tunnel on.
16
- The user said: "{{userMessage}}"
17
-
18
- Extract the port number from their message, or use the default port 3000 if not specified.
19
-
20
- Response format:
21
- \`\`\`json
22
- {
23
- "port": 3000
24
- }
25
- \`\`\`
26
- `;
27
-
28
- export const startTunnelAction: Action = {
29
- name: 'START_TUNNEL',
30
- similes: ['OPEN_TUNNEL', 'CREATE_TUNNEL', 'NGROK_START', 'TUNNEL_UP'],
31
- description:
32
- 'Start an ngrok tunnel to expose a local port to the internet. Supports action chaining by providing tunnel metadata that can be used for webhook configuration, API testing, or remote access workflows.',
33
- validate: async (runtime: IAgentRuntime, _message: Memory) => {
34
- const tunnelService = getTunnelService(runtime);
35
- if (!tunnelService) {
36
- return false;
37
- }
38
-
39
- // Check if tunnel is already active
40
- if (tunnelService.isActive()) {
41
- elizaLogger.warn('Tunnel is already active');
42
- return false;
43
- }
44
-
45
- return true;
46
- },
47
- handler: async (
48
- runtime: IAgentRuntime,
49
- message: Memory,
50
- _state?: State,
51
- _options?: unknown,
52
- callback?: HandlerCallback
53
- ): Promise<ActionResult> => {
54
- const tunnelService = getTunnelService(runtime);
55
- if (!tunnelService) {
56
- elizaLogger.error('Tunnel service is not available');
57
- if (callback) {
58
- await callback({
59
- text: 'Tunnel service is not available. Please ensure the ngrok plugin is properly configured.',
60
- });
61
- }
62
- return {
63
- success: false,
64
- text: 'Tunnel service is not available. Please ensure the ngrok plugin is properly configured.',
65
- values: { success: false, error: 'service_unavailable' },
66
- data: { action: 'START_TUNNEL' },
67
- };
68
- }
69
-
70
- if (tunnelService.isActive()) {
71
- elizaLogger.warn('Tunnel is already active');
72
- if (callback) {
73
- await callback({
74
- text: 'Tunnel is already active. Please stop the existing tunnel before starting a new one.',
75
- });
76
- }
77
- return {
78
- success: false,
79
- text: 'Tunnel is already active. Please stop the existing tunnel before starting a new one.',
80
- values: { success: false, error: 'tunnel_already_active' },
81
- data: { action: 'START_TUNNEL' },
82
- };
83
- }
84
-
85
- elizaLogger.info('Starting ngrok tunnel...');
86
-
87
- try {
88
- // Extract port from message — inline the user message into the prompt
89
- // (TEXT_SMALL no longer accepts a separate `context` param).
90
- const userMessage = message.content.text ?? '';
91
- const prompt = startTunnelTemplate.replace('{{userMessage}}', userMessage);
92
-
93
- const portResponse = await runtime.useModel(ModelType.TEXT_SMALL, {
94
- prompt,
95
- temperature: 0.3,
96
- });
97
-
98
- let port = 3000; // default
99
- try {
100
- const parsed = JSON.parse(portResponse);
101
- if (parsed.port) {
102
- // Handle both number and string port values
103
- const portNum = typeof parsed.port === 'string' ? parseInt(parsed.port, 10) : parsed.port;
104
- if (!Number.isNaN(portNum) && portNum > 0 && portNum <= 65535) {
105
- port = portNum;
106
- }
107
- }
108
- } catch {
109
- // Try to extract port from plain text response
110
- const portMatch = portResponse.match(/\b(\d{1,5})\b/);
111
- if (portMatch) {
112
- const portNum = parseInt(portMatch[1], 10);
113
- if (!Number.isNaN(portNum) && portNum > 0 && portNum <= 65535) {
114
- port = portNum;
115
- }
116
- }
117
- elizaLogger.warn('Failed to parse port from response, using default 3000');
118
- }
119
-
120
- const url = await tunnelService.startTunnel(port);
121
-
122
- const responseText = `āœ… Ngrok tunnel started successfully!\n\n🌐 Public URL: ${url}\nšŸ”Œ Local Port: ${port}\n\nYour local service is now accessible from the internet.`;
123
-
124
- if (callback) {
125
- await callback({
126
- text: responseText,
127
- metadata: {
128
- tunnelUrl: url,
129
- port,
130
- action: 'tunnel_started',
131
- },
132
- });
133
- }
134
-
135
- return {
136
- success: true,
137
- text: responseText,
138
- values: {
139
- success: true,
140
- tunnelUrl: url ?? null,
141
- port,
142
- isActive: true,
143
- },
144
- data: {
145
- action: 'START_TUNNEL',
146
- tunnelMetadata: {
147
- url: url ?? null,
148
- port,
149
- startedAt: new Date().toISOString(),
150
- provider: 'ngrok',
151
- },
152
- },
153
- };
154
- } catch (error) {
155
- const message = error instanceof Error ? error.message : String(error);
156
- const stack = error instanceof Error ? (error.stack ?? null) : null;
157
- elizaLogger.error(`Failed to start tunnel: ${message}`);
158
-
159
- if (callback) {
160
- await callback({
161
- text: `āŒ Failed to start ngrok tunnel: ${message}\n\nPlease make sure ngrok is installed and configured properly.`,
162
- metadata: {
163
- error: message,
164
- action: 'tunnel_failed',
165
- },
166
- });
167
- }
168
-
169
- return {
170
- success: false,
171
- text: `āŒ Failed to start ngrok tunnel: ${message}\n\nPlease make sure ngrok is installed and configured properly.`,
172
- values: {
173
- success: false,
174
- error: message,
175
- },
176
- data: {
177
- action: 'START_TUNNEL',
178
- errorType: 'tunnel_start_failed',
179
- errorDetails: stack,
180
- },
181
- };
182
- }
183
- },
184
- examples: [
185
- [
186
- {
187
- name: '{{user}}',
188
- content: {
189
- text: 'Start an ngrok tunnel on port 8080',
190
- },
191
- },
192
- {
193
- name: '{{agent}}',
194
- content: {
195
- text: 'āœ… Ngrok tunnel started successfully!\n\n🌐 Public URL: https://abc123.ngrok.io\nšŸ”Œ Local Port: 8080\n\nYour local service is now accessible from the internet.',
196
- actions: ['START_TUNNEL'],
197
- },
198
- },
199
- ],
200
- [
201
- {
202
- name: '{{user}}',
203
- content: {
204
- text: 'Create a tunnel for my API server and then test the webhook endpoint',
205
- },
206
- },
207
- {
208
- name: '{{agent}}',
209
- content: {
210
- text: "I'll start an ngrok tunnel for your API server and then test the webhook endpoint.",
211
- thought:
212
- 'User wants to expose their API server and test webhooks - I should create the tunnel first, then use the public URL for webhook testing.',
213
- actions: ['START_TUNNEL'],
214
- },
215
- },
216
- {
217
- name: '{{agent}}',
218
- content: {
219
- text: 'āœ… Ngrok tunnel started successfully!\n\n🌐 Public URL: https://xyz789.ngrok.io\nšŸ”Œ Local Port: 3000\n\nNow testing the webhook endpoint...',
220
- thought:
221
- 'Tunnel is active and I have the public URL. I can now test the webhook endpoint using this external URL.',
222
- actions: ['TEST_WEBHOOK'],
223
- },
224
- },
225
- ],
226
- [
227
- {
228
- name: '{{user}}',
229
- content: {
230
- text: 'Start tunnel on port 4000 and share the link in our team chat',
231
- },
232
- },
233
- {
234
- name: '{{agent}}',
235
- content: {
236
- text: "I'll start the ngrok tunnel on port 4000 and then share the public URL with your team.",
237
- thought:
238
- 'User wants to expose their local service and share the link - I need to start the tunnel first, then send a message with the URL.',
239
- actions: ['START_TUNNEL'],
240
- },
241
- },
242
- {
243
- name: '{{agent}}',
244
- content: {
245
- text: 'āœ… Ngrok tunnel started successfully on port 4000! Now sharing the link with your team.',
246
- thought:
247
- 'Tunnel is up and running. I can now send a message to the team chat with the public URL.',
248
- actions: ['SEND_MESSAGE'],
249
- },
250
- },
251
- ],
252
- ] as ActionExample[][],
253
- };
254
-
255
- export default startTunnelAction;
@@ -1,203 +0,0 @@
1
- import {
2
- type Action,
3
- type ActionExample,
4
- type ActionResult,
5
- elizaLogger,
6
- type HandlerCallback,
7
- type IAgentRuntime,
8
- type Memory,
9
- type State,
10
- } from '@elizaos/core';
11
- import { getTunnelService } from '@elizaos/plugin-tunnel';
12
-
13
- export const stopTunnelAction: Action = {
14
- name: 'STOP_TUNNEL',
15
- similes: ['CLOSE_TUNNEL', 'SHUTDOWN_TUNNEL', 'NGROK_STOP', 'TUNNEL_DOWN'],
16
- description:
17
- 'Stop the running ngrok tunnel and clean up resources. Can be chained with START_TUNNEL actions for tunnel rotation workflows or combined with deployment actions for automated service management.',
18
- validate: async (runtime: IAgentRuntime, _message: Memory) => {
19
- return !!getTunnelService(runtime);
20
- },
21
- handler: async (
22
- runtime: IAgentRuntime,
23
- _message: Memory,
24
- _state?: State,
25
- _options?: unknown,
26
- callback?: HandlerCallback
27
- ): Promise<ActionResult> => {
28
- const tunnelService = getTunnelService(runtime);
29
- if (!tunnelService) {
30
- elizaLogger.error('Tunnel service is not available');
31
- if (callback) {
32
- await callback({
33
- text: 'Tunnel service is not available. Please ensure the ngrok plugin is properly configured.',
34
- });
35
- }
36
- return {
37
- success: false,
38
- text: 'Tunnel service is not available. Please ensure the ngrok plugin is properly configured.',
39
- values: { success: false, error: 'service_unavailable' },
40
- data: { action: 'STOP_TUNNEL' },
41
- };
42
- }
43
-
44
- if (!tunnelService.isActive()) {
45
- elizaLogger.warn('No active tunnel to stop');
46
- if (callback) {
47
- await callback({
48
- text: 'No tunnel is currently running.',
49
- metadata: {
50
- action: 'tunnel_not_active',
51
- },
52
- });
53
- }
54
- return {
55
- success: true,
56
- text: 'No tunnel is currently running.',
57
- values: { success: true, wasActive: false },
58
- data: { action: 'STOP_TUNNEL', status: 'already_stopped' },
59
- };
60
- }
61
-
62
- elizaLogger.info('Stopping ngrok tunnel...');
63
-
64
- try {
65
- const status = tunnelService.getStatus();
66
- const previousUrl = status.url;
67
- const previousPort = status.port;
68
-
69
- await tunnelService.stopTunnel();
70
-
71
- const responseText = `āœ… Ngrok tunnel stopped successfully!\n\nšŸ”Œ Was running on port: ${previousPort}\n🌐 Previous URL: ${previousUrl}\n\nThe tunnel has been closed and is no longer accessible.`;
72
-
73
- if (callback) {
74
- await callback({
75
- text: responseText,
76
- metadata: {
77
- previousUrl,
78
- previousPort,
79
- action: 'tunnel_stopped',
80
- },
81
- });
82
- }
83
-
84
- return {
85
- success: true,
86
- text: responseText,
87
- values: {
88
- success: true,
89
- wasActive: true,
90
- previousUrl,
91
- previousPort,
92
- },
93
- data: {
94
- action: 'STOP_TUNNEL',
95
- previousTunnelMetadata: {
96
- url: previousUrl,
97
- port: previousPort,
98
- stoppedAt: new Date().toISOString(),
99
- },
100
- },
101
- };
102
- } catch (error) {
103
- const message = error instanceof Error ? error.message : String(error);
104
- const stack = error instanceof Error ? (error.stack ?? null) : null;
105
- elizaLogger.error(`Failed to stop tunnel: ${message}`);
106
-
107
- if (callback) {
108
- await callback({
109
- text: `āŒ Failed to stop ngrok tunnel: ${message}`,
110
- metadata: {
111
- error: message,
112
- action: 'tunnel_stop_failed',
113
- },
114
- });
115
- }
116
-
117
- return {
118
- success: false,
119
- text: `āŒ Failed to stop ngrok tunnel: ${message}`,
120
- values: {
121
- success: false,
122
- error: message,
123
- },
124
- data: {
125
- action: 'STOP_TUNNEL',
126
- errorType: 'tunnel_stop_failed',
127
- errorDetails: stack,
128
- },
129
- };
130
- }
131
- },
132
- examples: [
133
- [
134
- {
135
- name: '{{user}}',
136
- content: {
137
- text: 'Stop the ngrok tunnel',
138
- },
139
- },
140
- {
141
- name: '{{agent}}',
142
- content: {
143
- text: 'āœ… Ngrok tunnel stopped successfully!\n\nšŸ”Œ Was running on port: 3000\n🌐 Previous URL: https://abc123.ngrok.io\n\nThe tunnel has been closed and is no longer accessible.',
144
- actions: ['STOP_TUNNEL'],
145
- },
146
- },
147
- ],
148
- [
149
- {
150
- name: '{{user}}',
151
- content: {
152
- text: 'Stop the current tunnel and start a new one on port 8080',
153
- },
154
- },
155
- {
156
- name: '{{agent}}',
157
- content: {
158
- text: "I'll stop the current tunnel and then start a new one on port 8080.",
159
- thought:
160
- 'User wants to switch tunnels - I need to stop the current one first, then start a new tunnel on the specified port.',
161
- actions: ['STOP_TUNNEL'],
162
- },
163
- },
164
- {
165
- name: '{{agent}}',
166
- content: {
167
- text: 'āœ… Tunnel stopped successfully! Now starting new tunnel on port 8080...',
168
- thought:
169
- 'Current tunnel is closed. Now I can start the new tunnel on port 8080 as requested.',
170
- actions: ['START_TUNNEL'],
171
- },
172
- },
173
- ],
174
- [
175
- {
176
- name: '{{user}}',
177
- content: {
178
- text: 'Close the tunnel and deploy to production',
179
- },
180
- },
181
- {
182
- name: '{{agent}}',
183
- content: {
184
- text: "I'll stop the development tunnel and then proceed with the production deployment.",
185
- thought:
186
- 'User is ready to move from development to production - I should close the ngrok tunnel first, then handle the deployment process.',
187
- actions: ['STOP_TUNNEL'],
188
- },
189
- },
190
- {
191
- name: '{{agent}}',
192
- content: {
193
- text: 'Development tunnel closed successfully. Now initiating production deployment...',
194
- thought:
195
- 'Tunnel is down, development phase is complete. I can now proceed with the production deployment workflow.',
196
- actions: ['DEPLOY_PRODUCTION'],
197
- },
198
- },
199
- ],
200
- ] as ActionExample[][],
201
- };
202
-
203
- export default stopTunnelAction;