feat: add openclaw-plugin-dev skill
Plugin development reference and workflows based on real development experience (Dirigent, ContractorAgent, PrismFacet). Docs: structure, entry-point, hooks, tools, state, config, debugging Workflows: create-plugin, add-hook Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
This commit is contained in:
48
openclaw-plugin-dev/docs/state.md
Normal file
48
openclaw-plugin-dev/docs/state.md
Normal file
@@ -0,0 +1,48 @@
|
||||
# State Management
|
||||
|
||||
## Where to Store What
|
||||
|
||||
| Data Type | Location | Reason |
|
||||
|-----------|----------|--------|
|
||||
| Business state (maps, sets, caches) | `globalThis` | Module vars reset on hot reload |
|
||||
| Event dedup (WeakSet/Set) | `globalThis` | Same |
|
||||
| Gateway lifecycle flags | `globalThis` | Prevent double init |
|
||||
| Connection flags (WebSocket/TCP) | `globalThis` | Prevent duplicate connections |
|
||||
| Runtime references | `globalThis` | Closures need living instance |
|
||||
| Cross-plugin API objects (`__pluginId`) | `globalThis` | Other plugins access via globalThis |
|
||||
| Pure utility functions | Module-level | No state needed |
|
||||
| Persistent data | File + memory cache | Survives gateway restart |
|
||||
|
||||
## Cross-Plugin API Pattern
|
||||
|
||||
### Provider side
|
||||
|
||||
```typescript
|
||||
const _G = globalThis as Record<string, unknown>;
|
||||
|
||||
// Init shared objects once
|
||||
if (!(_G["_myRegistry"] instanceof MyRegistry)) {
|
||||
_G["_myRegistry"] = new MyRegistry();
|
||||
}
|
||||
|
||||
// Overwrite public API every register() (updates closures)
|
||||
_G["__myPlugin"] = {
|
||||
registry: _G["_myRegistry"],
|
||||
send: (msg) => (_G["_myRuntime"] as Runtime)?.send(msg) ?? false,
|
||||
};
|
||||
```
|
||||
|
||||
### Consumer side
|
||||
|
||||
```typescript
|
||||
const provider = (globalThis as any)["__myPlugin"];
|
||||
if (!provider) {
|
||||
console.error("[consumer] __myPlugin not found");
|
||||
return;
|
||||
}
|
||||
provider.registry.register("my_rule", handler);
|
||||
```
|
||||
|
||||
### Load Order
|
||||
|
||||
Provider must be listed before consumer in `plugins.allow`. Consumer must defend against provider not being loaded.
|
||||
Reference in New Issue
Block a user