openclaw-cascade-plugin 1.0.12 → 1.0.14

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 (80) hide show
  1. package/dist/grpc-client.d.ts +17 -0
  2. package/dist/grpc-client.d.ts.map +1 -0
  3. package/dist/grpc-client.js +154 -0
  4. package/dist/grpc-client.js.map +1 -0
  5. package/dist/index.d.ts +2 -3
  6. package/dist/index.d.ts.map +1 -1
  7. package/dist/index.js +14 -54
  8. package/dist/index.js.map +1 -1
  9. package/dist/test-utils/mocks.d.ts +6 -4
  10. package/dist/test-utils/mocks.d.ts.map +1 -1
  11. package/dist/test-utils/mocks.js +24 -14
  12. package/dist/test-utils/mocks.js.map +1 -1
  13. package/dist/tools/desktop-automation.d.ts +2 -7
  14. package/dist/tools/desktop-automation.d.ts.map +1 -1
  15. package/dist/tools/desktop-automation.js +64 -123
  16. package/dist/tools/desktop-automation.js.map +1 -1
  17. package/dist/tools/index.d.ts +3 -10
  18. package/dist/tools/index.d.ts.map +1 -1
  19. package/dist/tools/index.js +3 -17
  20. package/dist/tools/index.js.map +1 -1
  21. package/openclaw.plugin.json +1 -1
  22. package/package.json +13 -2
  23. package/proto/cascade.proto +297 -0
  24. package/PHASE1_SUMMARY.md +0 -191
  25. package/PHASE3_SUMMARY.md +0 -195
  26. package/dist/cascade-client.d.ts +0 -53
  27. package/dist/cascade-client.d.ts.map +0 -1
  28. package/dist/cascade-client.js +0 -179
  29. package/dist/cascade-client.js.map +0 -1
  30. package/dist/python-manager.d.ts +0 -59
  31. package/dist/python-manager.d.ts.map +0 -1
  32. package/dist/python-manager.js +0 -190
  33. package/dist/python-manager.js.map +0 -1
  34. package/dist/tools/api-tools.d.ts +0 -9
  35. package/dist/tools/api-tools.d.ts.map +0 -1
  36. package/dist/tools/api-tools.js +0 -102
  37. package/dist/tools/api-tools.js.map +0 -1
  38. package/dist/tools/sandbox-tools.d.ts +0 -9
  39. package/dist/tools/sandbox-tools.d.ts.map +0 -1
  40. package/dist/tools/sandbox-tools.js +0 -79
  41. package/dist/tools/sandbox-tools.js.map +0 -1
  42. package/dist/tools/web-automation.d.ts +0 -9
  43. package/dist/tools/web-automation.d.ts.map +0 -1
  44. package/dist/tools/web-automation.js +0 -471
  45. package/dist/tools/web-automation.js.map +0 -1
  46. package/jest.setup.js +0 -19
  47. package/openclaw-cascade-plugin-1.0.0.tgz +0 -0
  48. package/openclaw-cascade-plugin-1.0.10.tgz +0 -0
  49. package/openclaw-cascade-plugin-1.0.11.tgz +0 -0
  50. package/openclaw-cascade-plugin-1.0.12.tgz +0 -0
  51. package/openclaw-cascade-plugin-1.0.4.tgz +0 -0
  52. package/openclaw-cascade-plugin-1.0.6.tgz +0 -0
  53. package/openclaw-cascade-plugin-1.0.7.tgz +0 -0
  54. package/openclaw-cascade-plugin-1.0.8.tgz +0 -0
  55. package/openclaw-cascade-plugin-1.0.9.tgz +0 -0
  56. package/scripts/postinstall.js +0 -84
  57. package/src/a2a-client.ts +0 -66
  58. package/src/cascade-client.test.ts +0 -400
  59. package/src/cascade-client.ts +0 -198
  60. package/src/config.test.ts +0 -189
  61. package/src/config.ts +0 -137
  62. package/src/index.ts +0 -202
  63. package/src/python-manager.test.ts +0 -187
  64. package/src/python-manager.ts +0 -230
  65. package/src/test-utils/helpers.ts +0 -107
  66. package/src/test-utils/index.ts +0 -2
  67. package/src/test-utils/mocks.ts +0 -101
  68. package/src/tools/a2a-tools.ts +0 -162
  69. package/src/tools/api-tools.ts +0 -110
  70. package/src/tools/desktop-automation.test.ts +0 -308
  71. package/src/tools/desktop-automation.ts +0 -366
  72. package/src/tools/index.ts +0 -13
  73. package/src/tools/response-helpers.ts +0 -78
  74. package/src/tools/sandbox-tools.ts +0 -83
  75. package/src/tools/tool-registry.ts +0 -51
  76. package/src/tools/web-automation.test.ts +0 -177
  77. package/src/tools/web-automation.ts +0 -518
  78. package/src/types/index.ts +0 -133
  79. package/src/wsl.ts +0 -53
  80. package/tsconfig.json +0 -27
@@ -1,107 +0,0 @@
1
- /**
2
- * Test helper utilities
3
- */
4
-
5
- import { join } from 'path';
6
- import { mkdir, rm } from 'fs/promises';
7
-
8
- export interface TestConfig {
9
- cascadeGrpcEndpoint: string;
10
- cascadePythonPath?: string;
11
- firestoreProjectId?: string;
12
- firestoreCredentialsPath?: string;
13
- headless?: boolean;
14
- actionTimeoutMs?: number;
15
- enableA2A?: boolean;
16
- verbose?: boolean;
17
- }
18
-
19
- export function createMockConfig(overrides: Partial<TestConfig> = {}): TestConfig {
20
- return {
21
- cascadeGrpcEndpoint: 'localhost:50051',
22
- headless: false,
23
- actionTimeoutMs: 8000,
24
- enableA2A: true,
25
- verbose: false,
26
- ...overrides
27
- };
28
- }
29
-
30
- export async function withTempDir(fn: (dir: string) => Promise<void>): Promise<void> {
31
- const tmpDir = join(process.cwd(), '.test-tmp', Date.now().toString());
32
- await mkdir(tmpDir, { recursive: true });
33
-
34
- try {
35
- await fn(tmpDir);
36
- } finally {
37
- await rm(tmpDir, { recursive: true, force: true });
38
- }
39
- }
40
-
41
- export function waitForCondition(
42
- condition: () => boolean,
43
- timeout = 5000,
44
- interval = 100
45
- ): Promise<void> {
46
- return new Promise((resolve, reject) => {
47
- const start = Date.now();
48
- const check = () => {
49
- if (condition()) {
50
- resolve();
51
- } else if (Date.now() - start > timeout) {
52
- reject(new Error(`Timeout waiting for condition after ${timeout}ms`));
53
- } else {
54
- setTimeout(check, interval);
55
- }
56
- };
57
- check();
58
- });
59
- }
60
-
61
- export function generateBase64Image(size: number): string {
62
- // Generate fake base64 image data
63
- const chars = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/';
64
- let result = '';
65
- for (let i = 0; i < size; i++) {
66
- result += chars[Math.floor(Math.random() * chars.length)];
67
- }
68
- // Pad to multiple of 4 for valid base64
69
- while (result.length % 4 !== 0) {
70
- result += '=';
71
- }
72
- return result;
73
- }
74
-
75
- export function createMockSpawnImplementation(
76
- stdoutData: string | string[],
77
- exitCode = 0
78
- ): () => any {
79
- return () => {
80
- const { EventEmitter } = require('events');
81
- const stdout = new EventEmitter();
82
- const stderr = new EventEmitter();
83
-
84
- const proc = Object.assign(new EventEmitter(), {
85
- stdout,
86
- stderr,
87
- stdin: { write: jest.fn() },
88
- kill: jest.fn()
89
- });
90
-
91
- // Emit stdout data after a brief delay
92
- setTimeout(() => {
93
- const lines = Array.isArray(stdoutData) ? stdoutData : [stdoutData];
94
- lines.forEach(line => stdout.emit('data', line + '\n'));
95
-
96
- setTimeout(() => {
97
- proc.emit('close', exitCode);
98
- }, 10);
99
- }, 10);
100
-
101
- return proc;
102
- };
103
- }
104
-
105
- export function delay(ms: number): Promise<void> {
106
- return new Promise(resolve => setTimeout(resolve, ms));
107
- }
@@ -1,2 +0,0 @@
1
- export * from './mocks';
2
- export * from './helpers';
@@ -1,101 +0,0 @@
1
- /**
2
- * Mock implementations for testing
3
- */
4
-
5
- import { EventEmitter } from 'events';
6
-
7
- export interface MockChildProcess {
8
- stdout: EventEmitter;
9
- stderr: EventEmitter;
10
- stdin: {
11
- write: jest.Mock;
12
- };
13
- on: jest.Mock;
14
- once: jest.Mock;
15
- emit: jest.Mock;
16
- kill: jest.Mock;
17
- pid: number;
18
- connected: boolean;
19
- disconnect: jest.Mock;
20
- unref: jest.Mock;
21
- ref: jest.Mock;
22
- send: jest.Mock;
23
- }
24
-
25
- export function createMockChildProcess(): MockChildProcess {
26
- const stdout = new EventEmitter();
27
- const stderr = new EventEmitter();
28
-
29
- return {
30
- stdout,
31
- stderr,
32
- stdin: {
33
- write: jest.fn()
34
- },
35
- on: jest.fn(),
36
- once: jest.fn(),
37
- emit: jest.fn(),
38
- kill: jest.fn(),
39
- pid: 12345,
40
- connected: true,
41
- disconnect: jest.fn(),
42
- unref: jest.fn(),
43
- ref: jest.fn(),
44
- send: jest.fn()
45
- };
46
- }
47
-
48
- export class MockCascadeMcpClient {
49
- private tools = new Map<string, Function>();
50
- public callTool = jest.fn();
51
- public listTools = jest.fn();
52
- public isConnected = jest.fn().mockReturnValue(true);
53
-
54
- registerMockTool(name: string, handler: Function) {
55
- this.tools.set(name, handler);
56
- this.callTool.mockImplementation(async (toolName: string, args: any) => {
57
- if (toolName === name) {
58
- return handler(args);
59
- }
60
- throw new Error(`Unknown tool: ${toolName}`);
61
- });
62
- }
63
-
64
- simulateError(error: Error) {
65
- this.callTool.mockRejectedValue(error);
66
- }
67
-
68
- simulateConnectionError() {
69
- this.isConnected.mockReturnValue(false);
70
- }
71
- }
72
-
73
- export class MockFirestore {
74
- private data = new Map<string, any>();
75
-
76
- setDocument(path: string, data: any) {
77
- this.data.set(path, data);
78
- }
79
-
80
- collection(path: string) {
81
- return {
82
- get: async () => ({
83
- docs: Array.from(this.data.entries())
84
- .filter(([key]) => key.startsWith(path))
85
- .map(([key, value]) => ({
86
- id: key.split('/').pop(),
87
- data: () => value
88
- }))
89
- }),
90
- doc: (id: string) => ({
91
- get: async () => ({
92
- exists: this.data.has(`${path}/${id}`),
93
- data: () => this.data.get(`${path}/${id}`)
94
- }),
95
- set: async (data: any) => {
96
- this.data.set(`${path}/${id}`, data);
97
- }
98
- })
99
- };
100
- }
101
- }
@@ -1,162 +0,0 @@
1
- /**
2
- * A2A Tools (Agent-to-Agent)
3
- *
4
- * 3 tools for calling Cascade agents
5
- */
6
-
7
- import { ToolRegistry } from './tool-registry';
8
- import { CascadeA2AClient } from '../a2a-client';
9
- import { ToolResponse } from '../types';
10
- import { errorResponse, formatSuccess } from './response-helpers';
11
-
12
- export function registerA2ATools(registry: ToolRegistry, getA2aClient: () => Promise<CascadeA2AClient | null>): void {
13
- // 1. cascade_run_explorer
14
- registry.register({
15
- name: 'cascade_run_explorer',
16
- description: 'Launch Cascade Explorer agent to learn an application',
17
- inputSchema: {
18
- type: 'object',
19
- properties: {
20
- app_name: {
21
- type: 'string',
22
- description: 'Application name to explore'
23
- },
24
- instructions: {
25
- type: 'string',
26
- description: 'Specific instructions for exploration'
27
- },
28
- max_steps: {
29
- type: 'integer',
30
- default: 50,
31
- description: 'Maximum exploration steps'
32
- }
33
- },
34
- required: ['app_name']
35
- },
36
- handler: async (args): Promise<ToolResponse> => {
37
- try {
38
- if (!args.app_name) {
39
- return errorResponse('app_name is required');
40
- }
41
-
42
- await (await getA2aClient())?.sendToAgent('explorer', {
43
- type: 'start_exploration',
44
- appName: args.app_name,
45
- instructions: args.instructions || `Learn how to use ${args.app_name}`,
46
- maxSteps: args.max_steps || 50
47
- });
48
-
49
- return formatSuccess({
50
- message: 'Explorer agent started',
51
- app_name: args.app_name,
52
- status: 'running'
53
- });
54
- } catch (error) {
55
- return errorResponse(
56
- error instanceof Error ? error.message : 'Failed to start explorer',
57
- 'Ensure A2A is enabled in configuration (enableA2A: true)'
58
- );
59
- }
60
- }
61
- });
62
-
63
- // 2. cascade_run_worker
64
- registry.register({
65
- name: 'cascade_run_worker',
66
- description: 'Execute a task using Cascade Worker agent',
67
- inputSchema: {
68
- type: 'object',
69
- properties: {
70
- task: {
71
- type: 'string',
72
- description: 'Task description to execute'
73
- },
74
- skill_id: {
75
- type: 'string',
76
- description: 'Optional skill ID to use'
77
- },
78
- app_name: {
79
- type: 'string',
80
- description: 'Target application name'
81
- },
82
- inputs: {
83
- type: 'object',
84
- description: 'Optional inputs for the task',
85
- additionalProperties: true
86
- }
87
- },
88
- required: ['task']
89
- },
90
- handler: async (args): Promise<ToolResponse> => {
91
- try {
92
- if (!args.task) {
93
- return errorResponse('task is required');
94
- }
95
-
96
- await (await getA2aClient())?.sendToAgent('worker', {
97
- type: 'execute_task',
98
- task: args.task,
99
- skillId: args.skill_id,
100
- appName: args.app_name,
101
- inputs: args.inputs || {}
102
- });
103
-
104
- return formatSuccess({
105
- message: 'Worker agent started',
106
- task: args.task,
107
- status: 'running'
108
- });
109
- } catch (error) {
110
- return errorResponse(
111
- error instanceof Error ? error.message : 'Failed to start worker',
112
- 'Ensure A2A is enabled in configuration (enableA2A: true)'
113
- );
114
- }
115
- }
116
- });
117
-
118
- // 3. cascade_run_orchestrator
119
- registry.register({
120
- name: 'cascade_run_orchestrator',
121
- description: 'Use Cascade Orchestrator to coordinate multi-step tasks',
122
- inputSchema: {
123
- type: 'object',
124
- properties: {
125
- goal: {
126
- type: 'string',
127
- description: 'High-level goal to achieve'
128
- },
129
- require_approval: {
130
- type: 'boolean',
131
- default: true,
132
- description: 'Require approval before executing steps'
133
- }
134
- },
135
- required: ['goal']
136
- },
137
- handler: async (args): Promise<ToolResponse> => {
138
- try {
139
- if (!args.goal) {
140
- return errorResponse('goal is required');
141
- }
142
-
143
- await (await getA2aClient())?.sendToAgent('orchestrator', {
144
- type: 'coordinate',
145
- goal: args.goal,
146
- requireApproval: args.require_approval !== false
147
- });
148
-
149
- return formatSuccess({
150
- message: 'Orchestrator started',
151
- goal: args.goal,
152
- status: 'running'
153
- });
154
- } catch (error) {
155
- return errorResponse(
156
- error instanceof Error ? error.message : 'Failed to start orchestrator',
157
- 'Ensure A2A is enabled in configuration (enableA2A: true)'
158
- );
159
- }
160
- }
161
- });
162
- }
@@ -1,110 +0,0 @@
1
- /**
2
- * API Tools
3
- *
4
- * 2 tools for web API calls and search
5
- */
6
-
7
- import { ToolRegistry } from './tool-registry';
8
- import { CascadeMcpClient } from '../cascade-client';
9
- import { ToolResponse } from '../types';
10
- import { errorResponse, formatSuccess } from './response-helpers';
11
-
12
- export function registerApiTools(registry: ToolRegistry, getClient: () => Promise<CascadeMcpClient>): void {
13
- // 1. cascade_web_search
14
- registry.register({
15
- name: 'cascade_web_search',
16
- description: 'Search the web for information',
17
- inputSchema: {
18
- type: 'object',
19
- properties: {
20
- query: {
21
- type: 'string',
22
- description: 'Search query'
23
- },
24
- top_k: {
25
- type: 'integer',
26
- default: 5,
27
- description: 'Number of results to return'
28
- }
29
- },
30
- required: ['query']
31
- },
32
- handler: async (args): Promise<ToolResponse> => {
33
- try {
34
- if (!args.query) {
35
- return errorResponse('query is required');
36
- }
37
-
38
- const result = await (await getClient()).callTool('web_search', {
39
- query: args.query,
40
- top_k: args.top_k || 5
41
- });
42
- return formatSuccess(result);
43
- } catch (error) {
44
- return errorResponse(
45
- error instanceof Error ? error.message : 'Failed to search web',
46
- 'Check your network connection and API key if required'
47
- );
48
- }
49
- }
50
- });
51
-
52
- // 2. cascade_call_http_api
53
- registry.register({
54
- name: 'cascade_call_http_api',
55
- description: 'Execute an HTTP API request',
56
- inputSchema: {
57
- type: 'object',
58
- properties: {
59
- method: {
60
- type: 'string',
61
- enum: ['GET', 'POST', 'PUT', 'DELETE', 'PATCH'],
62
- description: 'HTTP method'
63
- },
64
- url: {
65
- type: 'string',
66
- description: 'Full URL to call'
67
- },
68
- headers: {
69
- type: 'object',
70
- description: 'Optional HTTP headers',
71
- additionalProperties: { type: 'string' }
72
- },
73
- body: {
74
- type: 'object',
75
- description: 'Optional request body (as JSON)'
76
- },
77
- timeout: {
78
- type: 'number',
79
- default: 30,
80
- description: 'Request timeout in seconds'
81
- }
82
- },
83
- required: ['method', 'url']
84
- },
85
- handler: async (args): Promise<ToolResponse> => {
86
- try {
87
- if (!args.method) {
88
- return errorResponse('method is required');
89
- }
90
- if (!args.url) {
91
- return errorResponse('url is required');
92
- }
93
-
94
- const result = await (await getClient()).callTool('call_http_api', {
95
- method: args.method,
96
- url: args.url,
97
- headers: args.headers,
98
- body: args.body,
99
- timeout: args.timeout || 30
100
- });
101
- return formatSuccess(result);
102
- } catch (error) {
103
- return errorResponse(
104
- error instanceof Error ? error.message : 'Failed to call API',
105
- 'Verify the URL is correct and the API is accessible'
106
- );
107
- }
108
- }
109
- });
110
- }