@alexma03/utcp-cli 1.1.0

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/README.md ADDED
@@ -0,0 +1,519 @@
1
+ # @utcp/cli: Command Line Interface Communication Protocol for UTCP
2
+
3
+ The `@utcp/cli` package enables the `UtcpClient` to interact with command-line tools and programs as UTCP tool providers. This plugin provides a cross-platform way to execute shell commands, scripts, and CLI utilities with full support for multi-step workflows, environment variables, and output chaining.
4
+
5
+ ## Features
6
+
7
+ * **Automatic Plugin Registration**: Registers automatically when imported—no manual setup required.
8
+ * **Cross-Platform Support**: Automatically generates platform-specific scripts:
9
+ * **Windows**: PowerShell scripts with proper error handling
10
+ * **Unix/Linux/macOS**: Bash scripts with shell compatibility
11
+ * **Multi-Command Workflows**: Execute multiple commands in sequence within a single subprocess, maintaining state between commands.
12
+ * **Output Chaining**: Reference previous command outputs using variables (`$CMD_0_OUTPUT`, `$CMD_1_OUTPUT`, etc.).
13
+ * **Argument Placeholders**: Use `UTCP_ARG_argname_UTCP_END` placeholders for dynamic argument substitution.
14
+ * **Environment Variables**: Configure custom environment variables with UTCP variable substitution support.
15
+ * **Working Directory**: Specify custom working directories for command execution.
16
+ * **Tool Discovery**: Automatically discover tools by executing a discovery command that outputs a UTCP manual.
17
+ * **Smart Output Handling**: Control which command outputs are included in the final result.
18
+ * **JSON Output Parsing**: Automatically parses JSON responses when detected.
19
+
20
+ ## Installation
21
+
22
+ ```bash
23
+ bun add @utcp/cli @utcp/sdk
24
+
25
+ # Or using npm
26
+ npm install @utcp/cli @utcp/sdk
27
+ ```
28
+
29
+ Note: `@utcp/sdk` is a peer dependency.
30
+
31
+ ## Usage
32
+
33
+ The CLI plugin registers automatically when you import it—no manual registration needed. Simply import from `@utcp/cli` to enable CLI support.
34
+
35
+ ```typescript
36
+ // From your application's entry point
37
+
38
+ import { UtcpClient } from '@utcp/sdk';
39
+ import { CliCallTemplateSerializer } from '@utcp/cli';
40
+
41
+ async function main() {
42
+ // Define a CLI CallTemplate for single command execution
43
+ const serializer = new CliCallTemplateSerializer();
44
+ const gitStatusTemplate = serializer.validateDict({
45
+ name: 'git_status_tool',
46
+ call_template_type: 'cli',
47
+ commands: [
48
+ {
49
+ command: 'git status --porcelain',
50
+ append_to_final_output: true
51
+ }
52
+ ],
53
+ working_dir: '/path/to/your/repo'
54
+ });
55
+
56
+ const client = await UtcpClient.create(process.cwd(), {
57
+ manual_call_templates: [gitStatusTemplate]
58
+ });
59
+
60
+ console.log('CLI Plugin active. Executing tools...');
61
+
62
+ // Call the CLI tool
63
+ try {
64
+ const result = await client.callTool('git_status_tool', {});
65
+ console.log('Git status result:', result);
66
+ } catch (error) {
67
+ console.error('Error calling CLI tool:', error);
68
+ }
69
+
70
+ await client.close();
71
+ }
72
+
73
+ main().catch(console.error);
74
+ ```
75
+
76
+ ## Advanced Configuration
77
+
78
+ ### Multi-Command Workflows
79
+
80
+ Execute multiple commands in sequence within a single subprocess. State (like directory changes) is maintained between commands:
81
+
82
+ ```typescript
83
+ const serializer = new CliCallTemplateSerializer();
84
+ const multiStepTemplate = serializer.validateDict({
85
+ name: 'multi_step_workflow',
86
+ call_template_type: 'cli',
87
+ commands: [
88
+ {
89
+ command: 'cd UTCP_ARG_target_dir_UTCP_END',
90
+ append_to_final_output: false // Don't include this output in final result
91
+ },
92
+ {
93
+ command: 'git pull origin main',
94
+ append_to_final_output: false // Don't include this output
95
+ },
96
+ {
97
+ command: 'npm install',
98
+ append_to_final_output: false // Don't include this output
99
+ },
100
+ {
101
+ command: 'npm test',
102
+ append_to_final_output: true // Include this output in final result
103
+ }
104
+ ]
105
+ });
106
+
107
+ // Call with arguments
108
+ const result = await client.callTool('multi_step_workflow', {
109
+ target_dir: '/path/to/project'
110
+ });
111
+ ```
112
+
113
+ ### Output Chaining
114
+
115
+ Reference the output of previous commands using variables:
116
+
117
+ ```typescript
118
+ const serializer = new CliCallTemplateSerializer();
119
+ const outputChainingTemplate = serializer.validateDict({
120
+ name: 'chained_commands',
121
+ call_template_type: 'cli',
122
+ commands: [
123
+ {
124
+ command: 'git rev-parse --short HEAD',
125
+ append_to_final_output: false
126
+ },
127
+ {
128
+ command: 'echo "Building version: $CMD_0_OUTPUT"',
129
+ append_to_final_output: false
130
+ },
131
+ {
132
+ command: 'docker build -t myapp:$CMD_0_OUTPUT .',
133
+ append_to_final_output: true
134
+ }
135
+ ]
136
+ });
137
+ ```
138
+
139
+ **Platform-Specific Variable Reference:**
140
+ - **PowerShell** (Windows): `$CMD_0_OUTPUT`, `$CMD_1_OUTPUT`, etc.
141
+ - **Bash** (Unix/Linux/macOS): `$CMD_0_OUTPUT`, `$CMD_1_OUTPUT`, etc.
142
+
143
+ ### Argument Placeholders
144
+
145
+ Use `UTCP_ARG_argname_UTCP_END` placeholders for dynamic argument substitution:
146
+
147
+ ```typescript
148
+ const serializer = new CliCallTemplateSerializer();
149
+ const templateWithArgs = serializer.validateDict({
150
+ name: 'deploy_service',
151
+ call_template_type: 'cli',
152
+ commands: [
153
+ {
154
+ command: 'kubectl set image deployment/UTCP_ARG_service_name_UTCP_END ' +
155
+ 'UTCP_ARG_service_name_UTCP_END=UTCP_ARG_image_tag_UTCP_END',
156
+ append_to_final_output: true
157
+ },
158
+ {
159
+ command: 'kubectl rollout status deployment/UTCP_ARG_service_name_UTCP_END',
160
+ append_to_final_output: true
161
+ }
162
+ ]
163
+ });
164
+
165
+ // Call with arguments - placeholders will be replaced
166
+ const result = await client.callTool('deploy_service', {
167
+ service_name: 'api-server',
168
+ image_tag: 'myapp:v1.2.3'
169
+ });
170
+ ```
171
+
172
+ ### Environment Variables
173
+
174
+ Configure custom environment variables with UTCP variable substitution:
175
+
176
+ ```typescript
177
+ const serializer = new CliCallTemplateSerializer();
178
+ const envVarTemplate = serializer.validateDict({
179
+ name: 'python_script',
180
+ call_template_type: 'cli',
181
+ commands: [
182
+ {
183
+ command: 'python analysis.py --input UTCP_ARG_input_file_UTCP_END'
184
+ }
185
+ ],
186
+ env_vars: {
187
+ PYTHONPATH: '/custom/python/path',
188
+ API_KEY: '${MY_API_KEY}', // Uses UTCP variable substitution
189
+ LOG_LEVEL: 'debug',
190
+ DATABASE_URL: '${DATABASE_URL}'
191
+ },
192
+ working_dir: '/path/to/scripts'
193
+ });
194
+
195
+ const client = await UtcpClient.create(process.cwd(), {
196
+ manual_call_templates: [envVarTemplate],
197
+ variables: {
198
+ python__script_MY_API_KEY: 'secret-key-123', // Namespaced variable
199
+ python__script_DATABASE_URL: 'postgresql://localhost/mydb' // Namespaced variable
200
+ }
201
+ });
202
+ ```
203
+
204
+ ### Tool Discovery
205
+
206
+ Create a CLI provider that discovers its tools dynamically:
207
+
208
+ ```typescript
209
+ // Your CLI script should output a UTCP manual when called with a discovery flag
210
+ const serializer = new CliCallTemplateSerializer();
211
+ const discoveryTemplate = serializer.validateDict({
212
+ name: 'my_cli_tools',
213
+ call_template_type: 'cli',
214
+ commands: [
215
+ {
216
+ command: 'node my-cli-tool.js --utcp-discover',
217
+ append_to_final_output: true
218
+ }
219
+ ]
220
+ });
221
+
222
+ const client = await UtcpClient.create(process.cwd(), {
223
+ manual_call_templates: [discoveryTemplate]
224
+ });
225
+
226
+ // Tools are automatically discovered and registered
227
+ const tools = await client.searchTools('my_cli_tools');
228
+ console.log('Discovered tools:', tools.map(t => t.name));
229
+ ```
230
+
231
+ **Example CLI Tool with Discovery:**
232
+
233
+ ```typescript
234
+ // my-cli-tool.ts
235
+ if (process.argv.includes('--utcp-discover')) {
236
+ const manual = {
237
+ utcp_version: "1.0.0",
238
+ manual_version: "1.0.0",
239
+ tools: [
240
+ {
241
+ name: "echo_cli",
242
+ description: "Echoes a message via CLI.",
243
+ inputs: {
244
+ type: "object",
245
+ properties: { message: { type: "string" } },
246
+ required: ["message"]
247
+ },
248
+ outputs: { type: "string" },
249
+ tags: ["cli", "echo"],
250
+ tool_call_template: {
251
+ name: "my_cli_tools",
252
+ call_template_type: "cli"
253
+ }
254
+ }
255
+ ]
256
+ };
257
+ console.log(JSON.stringify(manual));
258
+ process.exit(0);
259
+ }
260
+
261
+ // Handle other commands...
262
+ ```
263
+
264
+ ### Cross-Platform Commands
265
+
266
+ **Important:** Use platform-appropriate syntax for your commands:
267
+
268
+ **Windows (PowerShell):**
269
+ ```typescript
270
+ {
271
+ commands: [
272
+ { command: 'Get-ChildItem -Path UTCP_ARG_path_UTCP_END' },
273
+ { command: 'Set-Location -Path UTCP_ARG_new_dir_UTCP_END' }
274
+ ]
275
+ }
276
+ ```
277
+
278
+ **Unix/Linux/macOS (Bash):**
279
+ ```typescript
280
+ {
281
+ commands: [
282
+ { command: 'ls -la UTCP_ARG_path_UTCP_END' },
283
+ { command: 'cd UTCP_ARG_new_dir_UTCP_END' }
284
+ ]
285
+ }
286
+ ```
287
+
288
+ The CLI plugin automatically detects the platform and executes commands using the appropriate shell.
289
+
290
+ ## Output Control
291
+
292
+ Control which command outputs appear in the final result using `append_to_final_output`:
293
+
294
+ ```typescript
295
+ {
296
+ commands: [
297
+ {
298
+ command: 'git pull',
299
+ append_to_final_output: false // Don't include in result
300
+ },
301
+ {
302
+ command: 'npm test',
303
+ append_to_final_output: true // Include in result
304
+ },
305
+ {
306
+ command: 'npm run build',
307
+ append_to_final_output: true // Include in result
308
+ }
309
+ ]
310
+ }
311
+ ```
312
+
313
+ **Default Behavior:**
314
+ - If `append_to_final_output` is not specified, only the **last command's output** is included in the final result.
315
+ - Set explicitly to `true` or `false` to override this behavior for any command.
316
+
317
+ ## JSON Output Handling
318
+
319
+ The CLI plugin automatically detects and parses JSON output:
320
+
321
+ ```typescript
322
+ const serializer = new CliCallTemplateSerializer();
323
+ const jsonOutputTemplate = serializer.validateDict({
324
+ name: 'json_cli_tool',
325
+ call_template_type: 'cli',
326
+ commands: [
327
+ {
328
+ command: 'echo \'{"status": "success", "count": 42}\''
329
+ }
330
+ ]
331
+ });
332
+
333
+ const result = await client.callTool('json_cli_tool', {});
334
+ // result = { status: "success", count: 42 } // Automatically parsed as JSON
335
+ ```
336
+
337
+ If output doesn't start with `{` or `[`, it's returned as plain text.
338
+
339
+ ## Command Execution Details
340
+
341
+ ### Single Subprocess Execution
342
+
343
+ All commands in a template are executed in a **single subprocess**, which means:
344
+ - State is preserved between commands (e.g., directory changes with `cd`)
345
+ - Environment variables persist across commands
346
+ - Variables set in one command can be used in later commands
347
+
348
+ ### Script Generation
349
+
350
+ The plugin generates platform-specific scripts:
351
+
352
+ **Windows (PowerShell):**
353
+ ```powershell
354
+ $ErrorActionPreference = "Stop"
355
+ # Variables to store command outputs
356
+ $CMD_0_OUTPUT = git status 2>&1 | Out-String
357
+ $CMD_1_OUTPUT = echo "Status: $CMD_0_OUTPUT" 2>&1 | Out-String
358
+ Write-Output $CMD_1_OUTPUT
359
+ ```
360
+
361
+ **Unix (Bash):**
362
+ ```bash
363
+ #!/bin/bash
364
+ # Variables to store command outputs
365
+ CMD_0_OUTPUT=$(git status 2>&1)
366
+ CMD_1_OUTPUT=$(echo "Status: $CMD_0_OUTPUT" 2>&1)
367
+ echo "${CMD_1_OUTPUT}"
368
+ ```
369
+
370
+ ### Timeout Configuration
371
+
372
+ Default timeouts:
373
+ - **Tool Discovery**: 30 seconds
374
+ - **Tool Execution**: 120 seconds
375
+
376
+ These provide ample time for multi-command workflows.
377
+
378
+ ## API Reference
379
+
380
+ ### CliCallTemplate
381
+
382
+ ```typescript
383
+ interface CliCallTemplate {
384
+ name?: string;
385
+ call_template_type: 'cli';
386
+ commands: CommandStep[];
387
+ env_vars?: Record<string, string> | null;
388
+ working_dir?: string | null;
389
+ auth?: undefined; // Not applicable for CLI
390
+ }
391
+ ```
392
+
393
+ ### CommandStep
394
+
395
+ ```typescript
396
+ interface CommandStep {
397
+ command: string; // Command to execute with optional placeholders
398
+ append_to_final_output?: boolean; // Include in final result (default: true for last command only)
399
+ }
400
+ ```
401
+
402
+ ### Placeholder Syntax
403
+
404
+ - **Argument Placeholder**: `UTCP_ARG_argname_UTCP_END`
405
+ - Replaced with the value from `tool_args`
406
+ - Example: `UTCP_ARG_filename_UTCP_END` → `'myfile.txt'`
407
+
408
+ - **Output Reference**: `$CMD_N_OUTPUT` (where N is the command index starting from 0)
409
+ - References the output of previous commands
410
+ - Example: `$CMD_0_OUTPUT` → output from first command
411
+
412
+ ## Security Considerations
413
+
414
+ **⚠️ Important Security Notes:**
415
+
416
+ 1. **Trusted Commands Only**: Commands are executed in a subprocess. Only use CLI templates from trusted sources.
417
+ 2. **Avoid Unsanitized Input**: Do not pass unsanitized user input directly into command strings.
418
+ 3. **Command Injection**: Be cautious when using output references (`$CMD_N_OUTPUT`) to avoid command injection vulnerabilities.
419
+ 4. **Validate Arguments**: Use proper input validation in your tool definitions.
420
+ 5. **Environment Variables**: Be careful with sensitive data in environment variables.
421
+
422
+ ## Best Practices
423
+
424
+ 1. **Use Placeholders**: Always use `UTCP_ARG_*_UTCP_END` placeholders instead of string concatenation.
425
+ 2. **Explicit Output Control**: Explicitly set `append_to_final_output` for clarity in multi-command workflows.
426
+ 3. **Error Handling**: Wrap tool calls in try-catch blocks for robust error handling.
427
+ 4. **Working Directory**: Specify `working_dir` when commands depend on specific file locations.
428
+ 5. **Platform-Specific Syntax**: Use appropriate command syntax for your target platform(s).
429
+ 6. **Tool Discovery**: Implement discovery commands that output valid UTCP manuals for dynamic tool registration.
430
+ 7. **Timeouts**: Be mindful of execution time for long-running commands.
431
+
432
+ ## Examples
433
+
434
+ ### Basic File Operations
435
+
436
+ ```typescript
437
+ const serializer = new CliCallTemplateSerializer();
438
+ const fileOpsTemplate = serializer.validateDict({
439
+ name: 'file_operations',
440
+ call_template_type: 'cli',
441
+ commands: [
442
+ {
443
+ command: 'cat UTCP_ARG_filename_UTCP_END'
444
+ }
445
+ ]
446
+ });
447
+
448
+ const content = await client.callTool('file_operations', {
449
+ filename: '/path/to/file.txt'
450
+ });
451
+ ```
452
+
453
+ ### Build and Test Pipeline
454
+
455
+ ```typescript
456
+ const serializer = new CliCallTemplateSerializer();
457
+ const buildPipeline = serializer.validateDict({
458
+ name: 'build_and_test',
459
+ call_template_type: 'cli',
460
+ commands: [
461
+ {
462
+ command: 'npm run lint',
463
+ append_to_final_output: false
464
+ },
465
+ {
466
+ command: 'npm test',
467
+ append_to_final_output: true
468
+ },
469
+ {
470
+ command: 'npm run build',
471
+ append_to_final_output: true
472
+ }
473
+ ],
474
+ env_vars: {
475
+ NODE_ENV: 'production',
476
+ CI: 'true'
477
+ }
478
+ });
479
+ ```
480
+
481
+ ### Git Workflow
482
+
483
+ ```typescript
484
+ const serializer = new CliCallTemplateSerializer();
485
+ const gitWorkflow = serializer.validateDict({
486
+ name: 'git_commit_push',
487
+ call_template_type: 'cli',
488
+ commands: [
489
+ {
490
+ command: 'git add .',
491
+ append_to_final_output: false
492
+ },
493
+ {
494
+ command: 'git commit -m "UTCP_ARG_message_UTCP_END"',
495
+ append_to_final_output: false
496
+ },
497
+ {
498
+ command: 'git push origin UTCP_ARG_branch_UTCP_END',
499
+ append_to_final_output: true
500
+ }
501
+ ]
502
+ });
503
+
504
+ const result = await client.callTool('git_commit_push', {
505
+ message: 'feat: add new feature',
506
+ branch: 'main'
507
+ });
508
+ ```
509
+
510
+ ## Limitations
511
+
512
+ - **No Streaming Support**: The CLI protocol does not support streaming. All output is returned when the command completes.
513
+ - **Platform-Specific**: Commands must be written for the target platform (Windows/Unix).
514
+ - **No Interactive Commands**: Interactive CLI tools (that require user input) are not supported.
515
+ - **Fixed Timeouts**: Timeout durations are currently fixed (though generous).
516
+
517
+ ## License
518
+
519
+ This package is part of the UTCP project. See the main repository for license information.