Skip to content

Commit 42222d1

Browse files
authored
feat: include plugin commands in help (#15)
* docs: add detailed documentation for plugin help integration and metadata usage * fix: re-add missing cli * docs: add note on cross-platform compatibility for development * fix: update build script to include clean step before compilation * chore: remove obsolete plan documentation for c8ctl CLI * feat: enhance c8ctl plugin with custom commands for analysis and configuration management * feat: add sample JavaScript and TypeScript plugins demonstrating custom commands * feat: add TypeScript plugin with build configuration and .gitignore * chore: cleanup * feat: implement global c8ctl runtime for plugins and enhance plugin structure with TypeScript and JavaScript examples
1 parent a89c4bb commit 42222d1

21 files changed

+806
-318
lines changed

.github/copilot-instructions.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,7 @@ Follow conventions in COMMIT-MESSAGE-GUIDELINE.md.
1515
- this is a native Node.js project running TS files
1616
- there is no build step for development. Only compile for test purposes or release.
1717

18+
- pay attention on cross-platform compatibility (Linux, MacOS, Windows). _BUT_ only cater to WSL on Windows, no native Windows support.
1819
- prefer functional programming over OOP where reasonable
1920
- prefer concise expressions over verbose control structures
2021

PLUGIN-HELP.md

Lines changed: 202 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,202 @@
1+
# Plugin Help Integration
2+
3+
This document describes how c8ctl plugins can provide help text that gets integrated into the main `c8ctl help` command.
4+
5+
## Overview
6+
7+
When users load plugins, their commands automatically appear in the help text. Plugins can optionally provide descriptions for their commands to make the help more informative.
8+
9+
## How It Works
10+
11+
1. **Automatic Discovery**: When `c8ctl help` is invoked, it scans all loaded plugins
12+
2. **Plugin Section**: If plugins are loaded, a "Plugin Commands" section appears at the bottom of the help text
13+
3. **Command Listing**: Each plugin command is listed with its optional description
14+
15+
## Plugin Structure for Help
16+
17+
Plugins can export an optional `metadata` object alongside the required `commands` object:
18+
19+
### TypeScript Example
20+
21+
```typescript
22+
import { c8ctl } from 'c8ctl/runtime';
23+
24+
// Optional metadata export for help text
25+
export const metadata = {
26+
name: 'my-awesome-plugin',
27+
description: 'My custom c8ctl plugin',
28+
commands: {
29+
analyze: {
30+
description: 'Analyze BPMN processes for best practices',
31+
},
32+
optimize: {
33+
description: 'Optimize process definitions',
34+
},
35+
},
36+
};
37+
38+
// Required commands export
39+
export const commands = {
40+
analyze: async (args: string[]) => {
41+
console.log('Analyzing...');
42+
// implementation
43+
},
44+
45+
optimize: async (args: string[]) => {
46+
console.log('Optimizing...');
47+
// implementation
48+
},
49+
};
50+
```
51+
52+
### JavaScript Example
53+
54+
```javascript
55+
import { c8ctl } from 'c8ctl/runtime';
56+
57+
// Optional metadata export
58+
export const metadata = {
59+
name: 'my-plugin',
60+
description: 'My plugin for c8ctl',
61+
commands: {
62+
'deploy-all': {
63+
description: 'Deploy all resources in a directory',
64+
},
65+
status: {
66+
description: 'Check cluster status',
67+
},
68+
},
69+
};
70+
71+
// Required commands export
72+
export const commands = {
73+
'deploy-all': async (args) => {
74+
console.log('Deploying all...');
75+
},
76+
77+
status: async (args) => {
78+
console.log('Checking status...');
79+
},
80+
};
81+
```
82+
83+
## Help Output Example
84+
85+
Without plugins loaded:
86+
```
87+
c8ctl - Camunda 8 CLI v2.0.0
88+
89+
Usage: c8ctl <command> [resource] [options]
90+
91+
Commands:
92+
list <resource> List resources (pi, ut, inc, jobs, profiles)
93+
get <resource> <key> Get resource by key (pi, topology)
94+
...
95+
```
96+
97+
With plugins loaded:
98+
```
99+
c8ctl - Camunda 8 CLI v2.0.0
100+
101+
Usage: c8ctl <command> [resource] [options]
102+
103+
Commands:
104+
list <resource> List resources (pi, ut, inc, jobs, profiles)
105+
get <resource> <key> Get resource by key (pi, topology)
106+
...
107+
108+
Plugin Commands:
109+
analyze Analyze BPMN processes for best practices
110+
optimize Optimize process definitions
111+
deploy-all Deploy all resources in a directory
112+
status Check cluster status
113+
```
114+
115+
## Implementation Details
116+
117+
### Plugin Loader
118+
119+
The plugin loader ([src/plugin-loader.ts](src/plugin-loader.ts)) provides:
120+
121+
- `getPluginCommandNames()`: Returns array of command names
122+
- `getPluginCommandsInfo()`: Returns detailed info including descriptions
123+
- Automatic metadata extraction during plugin loading
124+
125+
### Help Command
126+
127+
The help command ([src/commands/help.ts](src/commands/help.ts)):
128+
129+
1. Calls `getPluginCommandsInfo()` to retrieve plugin information
130+
2. Builds a "Plugin Commands" section if plugins are loaded
131+
3. Formats commands with descriptions (if available)
132+
133+
### Metadata Structure
134+
135+
```typescript
136+
interface PluginMetadata {
137+
name?: string; // Plugin display name (optional)
138+
description?: string; // Plugin description (optional)
139+
commands?: {
140+
[commandName: string]: {
141+
description?: string; // Command description (shown in help)
142+
};
143+
};
144+
}
145+
```
146+
147+
## Best Practices
148+
149+
1. **Always provide descriptions**: Helps users discover and understand your commands
150+
2. **Keep descriptions concise**: Aim for one line (< 60 characters)
151+
3. **Use imperative verbs**: Start with action words (Analyze, Deploy, Check, etc.)
152+
4. **Match command names**: Ensure metadata command names match exported functions
153+
5. **TypeScript plugins**: The `c8ctl-plugin.js` entry point must be JavaScript. Node.js doesn't support type stripping in `node_modules`. Transpile TypeScript to JavaScript before publishing your plugin.
154+
155+
## Testing
156+
157+
See [tests/unit/plugin-loader.test.ts](tests/unit/plugin-loader.test.ts) for unit tests that verify:
158+
- `getPluginCommandsInfo()` returns correct structure
159+
- Help text includes plugin commands
160+
- Metadata is properly parsed
161+
162+
## Example Plugin Development Flow
163+
164+
1. Create plugin with commands:
165+
```typescript
166+
export const commands = {
167+
myCommand: async () => { /* ... */ }
168+
};
169+
```
170+
171+
2. Add metadata for help:
172+
```typescript
173+
export const metadata = {
174+
commands: {
175+
myCommand: {
176+
description: 'Description shown in help'
177+
}
178+
}
179+
};
180+
```
181+
182+
3. Load plugin:
183+
```bash
184+
c8ctl load plugin my-plugin
185+
```
186+
187+
4. Verify help includes your command:
188+
```bash
189+
c8ctl help
190+
```
191+
192+
## Migration for Existing Plugins
193+
194+
Existing plugins without metadata will still work! Their commands will appear in the help text without descriptions:
195+
196+
```
197+
Plugin Commands:
198+
mycommand
199+
anothercommand
200+
```
201+
202+
To add descriptions, simply export a `metadata` object as shown above.

README.md

Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -226,25 +226,42 @@ c8ctl unload plugin <package-name>
226226

227227
# List installed plugins
228228
c8ctl list plugins
229+
230+
# View help including plugin commands
231+
c8ctl help
229232
```
230233

231234
**Plugin Requirements:**
232235
- Plugin packages must be regular Node.js modules
233236
- They must include a `c8ctl-plugin.js` or `c8ctl-plugin.ts` file in the root directory
234237
- The plugin file must export a `commands` object
238+
- Optionally export a `metadata` object to provide help text
235239
- Plugins are installed in `node_modules` like regular npm packages
236240
- The runtime object `c8ctl` provides environment information to plugins
241+
- **Important**: `c8ctl-plugin.js` must be JavaScript. Node.js doesn't support type stripping in `node_modules`. If writing in TypeScript, transpile to JS before publishing.
237242

238243
**Example Plugin Structure:**
239244
```typescript
240245
// c8ctl-plugin.ts
246+
export const metadata = {
247+
name: 'my-plugin',
248+
description: 'My custom c8ctl plugin',
249+
commands: {
250+
analyze: {
251+
description: 'Analyze BPMN processes'
252+
}
253+
}
254+
};
255+
241256
export const commands = {
242257
analyze: async (args: string[]) => {
243258
console.log('Analyzing...', args);
244259
}
245260
};
246261
```
247262

263+
When plugins are loaded, their commands automatically appear in `c8ctl help` output. See [PLUGIN-HELP.md](PLUGIN-HELP.md) for detailed documentation on plugin help integration.
264+
248265
### Resource Aliases
249266

250267
- `pi` = process-instance(s)
@@ -315,8 +332,15 @@ c8 <command>
315332

316333
# For local development with Node.js 22.18+ (native TypeScript)
317334
node src/index.ts <command>
335+
336+
# Testing with npm link (requires build first)
337+
npm run build
338+
npm link
339+
c8ctl <command>
318340
```
319341

342+
**Note**: The build step is only required for publishing or using `npm link`. Development uses native TypeScript execution via `node src/index.ts`.
343+
320344
### Adding New Commands
321345

322346
1. Create command handler in `src/commands/`

package.json

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -19,12 +19,14 @@
1919
"LICENSE"
2020
],
2121
"scripts": {
22-
"build": "tsc",
22+
"build": "npm run clean && tsc",
23+
"clean": "node -e \"require('fs').rmSync('dist',{recursive:true,force:true})\"",
2324
"prepublishOnly": "npm run build",
2425
"test": "node --test tests/unit/setup.test.ts tests/unit/*.test.ts tests/integration/*.test.ts",
2526
"test:unit": "node --test tests/unit/setup.test.ts tests/unit/*.test.ts",
2627
"test:integration": "node --test tests/integration/*.test.ts",
27-
"dev": "node src/index.ts"
28+
"dev": "node src/index.ts",
29+
"cli": "node src/index.ts"
2830
},
2931
"keywords": [
3032
"camunda",

0 commit comments

Comments
 (0)