@calimero-network/agent-skills 0.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 +238 -0
- package/SKILL.md +43 -0
- package/package.json +43 -0
- package/scripts/install.js +116 -0
- package/scripts/test.js +67 -0
- package/skills/calimero-abi-codegen/SKILL.md +61 -0
- package/skills/calimero-abi-codegen/references/abi-format.md +105 -0
- package/skills/calimero-abi-codegen/references/generated-output.md +89 -0
- package/skills/calimero-abi-codegen/references/programmatic-api.md +53 -0
- package/skills/calimero-abi-codegen/rules/schema-version.md +36 -0
- package/skills/calimero-abi-codegen/rules/unique-names.md +52 -0
- package/skills/calimero-client-js/SKILL.md +44 -0
- package/skills/calimero-client-js/references/auth.md +58 -0
- package/skills/calimero-client-js/references/rpc-calls.md +75 -0
- package/skills/calimero-client-js/references/sso.md +67 -0
- package/skills/calimero-client-js/references/websocket-events.md +66 -0
- package/skills/calimero-client-js/rules/camelcase-api.md +37 -0
- package/skills/calimero-client-js/rules/token-refresh.md +41 -0
- package/skills/calimero-client-py/SKILL.md +53 -0
- package/skills/calimero-client-py/references/api.md +147 -0
- package/skills/calimero-client-py/references/auth.md +72 -0
- package/skills/calimero-client-py/rules/async-usage.md +52 -0
- package/skills/calimero-client-py/rules/stable-node-name.md +39 -0
- package/skills/calimero-desktop/SKILL.md +47 -0
- package/skills/calimero-desktop/references/sso-integration.md +92 -0
- package/skills/calimero-desktop/rules/sso-fallback.md +33 -0
- package/skills/calimero-merobox/SKILL.md +55 -0
- package/skills/calimero-merobox/references/ci-integration.md +52 -0
- package/skills/calimero-merobox/references/workflow-files.md +70 -0
- package/skills/calimero-merobox/rules/docker-required.md +26 -0
- package/skills/calimero-node/SKILL.md +34 -0
- package/skills/calimero-node/references/context-lifecycle.md +59 -0
- package/skills/calimero-node/references/meroctl-commands.md +80 -0
- package/skills/calimero-node/rules/app-vs-context.md +33 -0
- package/skills/calimero-registry/SKILL.md +51 -0
- package/skills/calimero-registry/references/bundle-and-push.md +69 -0
- package/skills/calimero-registry/references/manifest-format.md +63 -0
- package/skills/calimero-registry/references/mero-sign.md +75 -0
- package/skills/calimero-registry/rules/key-security.md +41 -0
- package/skills/calimero-registry/rules/sign-before-pack.md +25 -0
- package/skills/calimero-rust-sdk/SKILL.md +73 -0
- package/skills/calimero-rust-sdk/references/events.md +53 -0
- package/skills/calimero-rust-sdk/references/examples.md +70 -0
- package/skills/calimero-rust-sdk/references/private-storage.md +56 -0
- package/skills/calimero-rust-sdk/references/state-collections.md +50 -0
- package/skills/calimero-rust-sdk/rules/app-macro-placement.md +34 -0
- package/skills/calimero-rust-sdk/rules/no-std-collections.md +27 -0
- package/skills/calimero-rust-sdk/rules/wasm-constraints.md +35 -0
package/README.md
ADDED
|
@@ -0,0 +1,238 @@
|
|
|
1
|
+
# @calimero-network/agent-skills
|
|
2
|
+
|
|
3
|
+
AI agent skills for [Calimero Network](https://calimero.network) development.
|
|
4
|
+
|
|
5
|
+
Install these skills into your project to give AI coding assistants (Claude, Cursor, Copilot)
|
|
6
|
+
accurate knowledge of the Calimero SDK, client libraries, registry tooling, and more — without
|
|
7
|
+
hallucinating APIs that don't exist.
|
|
8
|
+
|
|
9
|
+
## Skills
|
|
10
|
+
|
|
11
|
+
| Skill | When to use |
|
|
12
|
+
| --- | --- |
|
|
13
|
+
| [`calimero-rust-sdk`](#calimero-rust-sdk) | Building Rust WASM applications |
|
|
14
|
+
| [`calimero-client-js`](#calimero-client-js) | Frontend / Node.js clients connecting to a node |
|
|
15
|
+
| [`calimero-registry`](#calimero-registry) | Signing and publishing apps to the registry |
|
|
16
|
+
| [`calimero-desktop`](#calimero-desktop) | Integrating apps with Calimero Desktop SSO |
|
|
17
|
+
| [`calimero-node`](#calimero-node) | Node operators and meroctl scripting |
|
|
18
|
+
| [`calimero-merobox`](#calimero-merobox) | Local multi-node dev environments and CI |
|
|
19
|
+
| [`calimero-client-py`](#calimero-client-py) | Python client for node automation and backend services |
|
|
20
|
+
| [`calimero-abi-codegen`](#calimero-abi-codegen) | Generate TypeScript clients from WASM ABI manifests |
|
|
21
|
+
|
|
22
|
+
## Install
|
|
23
|
+
|
|
24
|
+
```bash
|
|
25
|
+
# Install a specific skill (writes to CLAUDE.md by default)
|
|
26
|
+
npx @calimero-network/agent-skills calimero-rust-sdk
|
|
27
|
+
|
|
28
|
+
# Target a specific editor
|
|
29
|
+
npx @calimero-network/agent-skills calimero-rust-sdk --cursor
|
|
30
|
+
npx @calimero-network/agent-skills calimero-rust-sdk --copilot
|
|
31
|
+
|
|
32
|
+
# List available skills
|
|
33
|
+
npx @calimero-network/agent-skills --list
|
|
34
|
+
```
|
|
35
|
+
|
|
36
|
+
### Where skill files are written
|
|
37
|
+
|
|
38
|
+
| Flag | File |
|
|
39
|
+
| --- | --- |
|
|
40
|
+
| (default) | `CLAUDE.md` |
|
|
41
|
+
| `--cursor` | `.cursorrules` |
|
|
42
|
+
| `--copilot` | `.github/copilot-instructions.md` |
|
|
43
|
+
|
|
44
|
+
Running the install again updates the existing block without duplicating it.
|
|
45
|
+
|
|
46
|
+
---
|
|
47
|
+
|
|
48
|
+
## Skill reference
|
|
49
|
+
|
|
50
|
+
### calimero-rust-sdk
|
|
51
|
+
|
|
52
|
+
For developers building **Calimero WASM applications** in Rust.
|
|
53
|
+
|
|
54
|
+
Covers:
|
|
55
|
+
- App skeleton with `#[app]` macros
|
|
56
|
+
- CRDT state collections (`UnorderedMap`, `Vector`, `Set`)
|
|
57
|
+
- Event emission with `app::emit!()`
|
|
58
|
+
- Private vs shared storage
|
|
59
|
+
- WASM runtime constraints (no threads, no `async`, no std I/O)
|
|
60
|
+
- Reference examples (kv-store, collaborative-editor)
|
|
61
|
+
|
|
62
|
+
Key rules included:
|
|
63
|
+
- Never use `std::collections` for state — CRDT collections only
|
|
64
|
+
- `#[app]` macro goes on the `impl` block, not the struct
|
|
65
|
+
- No `println!` — use `env::log()`
|
|
66
|
+
|
|
67
|
+
```bash
|
|
68
|
+
npx @calimero-network/agent-skills calimero-rust-sdk
|
|
69
|
+
```
|
|
70
|
+
|
|
71
|
+
---
|
|
72
|
+
|
|
73
|
+
### calimero-client-js
|
|
74
|
+
|
|
75
|
+
For developers building **frontends or Node.js services** that connect to a Calimero node.
|
|
76
|
+
|
|
77
|
+
Covers:
|
|
78
|
+
- Authentication and token storage
|
|
79
|
+
- JSON-RPC calls (mutations and views)
|
|
80
|
+
- WebSocket event subscriptions
|
|
81
|
+
- SSO token reading from URL hash
|
|
82
|
+
|
|
83
|
+
Key rules included:
|
|
84
|
+
- `mero-js` v2 uses camelCase (`contextId`, not `context_id`)
|
|
85
|
+
- Always handle 401 with token refresh before surfacing errors
|
|
86
|
+
|
|
87
|
+
```bash
|
|
88
|
+
npx @calimero-network/agent-skills calimero-client-js
|
|
89
|
+
```
|
|
90
|
+
|
|
91
|
+
---
|
|
92
|
+
|
|
93
|
+
### calimero-registry
|
|
94
|
+
|
|
95
|
+
For developers **publishing apps** to the Calimero App Registry.
|
|
96
|
+
|
|
97
|
+
Covers:
|
|
98
|
+
- `mero-sign` installation (crates.io and from source)
|
|
99
|
+
- Key generation and security
|
|
100
|
+
- `manifest.json` format and required fields
|
|
101
|
+
- Signing workflow (RFC 8785 canonicalization + Ed25519)
|
|
102
|
+
- `calimero-registry bundle create` and `bundle push`
|
|
103
|
+
- Team / org signing patterns
|
|
104
|
+
|
|
105
|
+
Key rules included:
|
|
106
|
+
- Sign the manifest **before** bundling — not after
|
|
107
|
+
- Never commit `key.json` to version control
|
|
108
|
+
|
|
109
|
+
```bash
|
|
110
|
+
npx @calimero-network/agent-skills calimero-registry
|
|
111
|
+
```
|
|
112
|
+
|
|
113
|
+
---
|
|
114
|
+
|
|
115
|
+
### calimero-desktop
|
|
116
|
+
|
|
117
|
+
For developers **integrating their app frontend** with Calimero Desktop SSO.
|
|
118
|
+
|
|
119
|
+
Covers:
|
|
120
|
+
- Hash params passed by Desktop (`access_token`, `refresh_token`, `node_url`, `application_id`)
|
|
121
|
+
- Full startup integration pattern (React and vanilla JS)
|
|
122
|
+
- How Desktop discovers the app's frontend URL (`manifest.json` `links.frontend`)
|
|
123
|
+
|
|
124
|
+
Key rules included:
|
|
125
|
+
- Always fall back to manual login when hash params are absent
|
|
126
|
+
|
|
127
|
+
```bash
|
|
128
|
+
npx @calimero-network/agent-skills calimero-desktop
|
|
129
|
+
```
|
|
130
|
+
|
|
131
|
+
---
|
|
132
|
+
|
|
133
|
+
### calimero-node
|
|
134
|
+
|
|
135
|
+
For **node operators** and developers scripting against a live node.
|
|
136
|
+
|
|
137
|
+
Covers:
|
|
138
|
+
- `merod` startup and configuration
|
|
139
|
+
- Full `meroctl` command reference (app, context, identity, call)
|
|
140
|
+
- Context lifecycle (app install → context create → invite → join → sync)
|
|
141
|
+
|
|
142
|
+
Key rules included:
|
|
143
|
+
- Application and context are different — installing an app does not create a context
|
|
144
|
+
|
|
145
|
+
```bash
|
|
146
|
+
npx @calimero-network/agent-skills calimero-node
|
|
147
|
+
```
|
|
148
|
+
|
|
149
|
+
---
|
|
150
|
+
|
|
151
|
+
### calimero-merobox
|
|
152
|
+
|
|
153
|
+
For developers setting up **local multi-node environments** or CI pipelines.
|
|
154
|
+
|
|
155
|
+
Covers:
|
|
156
|
+
- Merobox installation
|
|
157
|
+
- Workflow YAML format
|
|
158
|
+
- Multi-node setup with app deployment and context creation
|
|
159
|
+
- GitHub Actions integration template
|
|
160
|
+
|
|
161
|
+
Key rules included:
|
|
162
|
+
- Docker must be running before any merobox command
|
|
163
|
+
|
|
164
|
+
```bash
|
|
165
|
+
npx @calimero-network/agent-skills calimero-merobox
|
|
166
|
+
```
|
|
167
|
+
|
|
168
|
+
---
|
|
169
|
+
|
|
170
|
+
### calimero-client-py
|
|
171
|
+
|
|
172
|
+
For developers using the **Python client** to automate or script against a Calimero node.
|
|
173
|
+
|
|
174
|
+
Covers:
|
|
175
|
+
- Full async API (contexts, apps, identities, blobs, aliases, proposals)
|
|
176
|
+
- Authentication and token caching (`~/.merobox/auth_cache/`)
|
|
177
|
+
- First-time token seeding and CI/CD patterns
|
|
178
|
+
|
|
179
|
+
Key rules included:
|
|
180
|
+
- `node_name` must be stable and unique per node — changing it loses cached tokens
|
|
181
|
+
- All client methods are async and must be awaited
|
|
182
|
+
|
|
183
|
+
```bash
|
|
184
|
+
npx @calimero-network/agent-skills calimero-client-py
|
|
185
|
+
```
|
|
186
|
+
|
|
187
|
+
---
|
|
188
|
+
|
|
189
|
+
### calimero-abi-codegen
|
|
190
|
+
|
|
191
|
+
For developers **generating typed TypeScript clients** from a Calimero app's ABI manifest.
|
|
192
|
+
|
|
193
|
+
Covers:
|
|
194
|
+
- CLI usage (`npx calimero-abi-codegen -i abi.json -o src/generated`)
|
|
195
|
+
- ABI manifest format (`wasm-abi/1` schema, types, methods, events)
|
|
196
|
+
- Generated output shape (`types.ts` + `{ClientName}.ts`)
|
|
197
|
+
- Programmatic API for custom codegen pipelines
|
|
198
|
+
- Integrating codegen into your build script
|
|
199
|
+
|
|
200
|
+
Key rules included:
|
|
201
|
+
- ABI must have `"schema_version": "wasm-abi/1"` — other values are rejected
|
|
202
|
+
- Method, event, and type names must all be unique; map keys must be string
|
|
203
|
+
|
|
204
|
+
```bash
|
|
205
|
+
npx @calimero-network/agent-skills calimero-abi-codegen
|
|
206
|
+
```
|
|
207
|
+
|
|
208
|
+
---
|
|
209
|
+
|
|
210
|
+
## Structure
|
|
211
|
+
|
|
212
|
+
Each skill follows this layout:
|
|
213
|
+
|
|
214
|
+
```
|
|
215
|
+
skills/<skill-name>/
|
|
216
|
+
├── SKILL.md # Agent instructions: what to know, what to avoid
|
|
217
|
+
├── references/ # Detailed API guides with real code examples
|
|
218
|
+
└── rules/ # Hard rules: one file per rule, named after the rule
|
|
219
|
+
```
|
|
220
|
+
|
|
221
|
+
The install script appends skill content to your editor's context file, wrapped in
|
|
222
|
+
markers so re-running updates the block cleanly.
|
|
223
|
+
|
|
224
|
+
## Contributing
|
|
225
|
+
|
|
226
|
+
See [CONTRIBUTING.md](CONTRIBUTING.md) for how to add or update a skill.
|
|
227
|
+
|
|
228
|
+
Skills should be:
|
|
229
|
+
- Based on real API surfaces, not pseudocode
|
|
230
|
+
- Focused on code examples over prose
|
|
231
|
+
- Kept up to date with library releases
|
|
232
|
+
|
|
233
|
+
## Links
|
|
234
|
+
|
|
235
|
+
- [Calimero Network](https://calimero.network)
|
|
236
|
+
- [Documentation](https://docs.calimero.network)
|
|
237
|
+
- [GitHub org](https://github.com/calimero-network)
|
|
238
|
+
- [Discord](https://discord.gg/urJeMtRRMu)
|
package/SKILL.md
ADDED
|
@@ -0,0 +1,43 @@
|
|
|
1
|
+
# Calimero Network — Agent Skills
|
|
2
|
+
|
|
3
|
+
This package provides AI agent skills for building on the Calimero Network stack.
|
|
4
|
+
|
|
5
|
+
## Available Skills
|
|
6
|
+
|
|
7
|
+
| Skill | Install command | When to use |
|
|
8
|
+
| --- | --- | --- |
|
|
9
|
+
| `calimero-rust-sdk` | `npx @calimero-network/agent-skills calimero-rust-sdk` | Building Rust WASM applications |
|
|
10
|
+
| `calimero-client-js` | `npx @calimero-network/agent-skills calimero-client-js` | Frontend / Node.js clients connecting to a node |
|
|
11
|
+
| `calimero-registry` | `npx @calimero-network/agent-skills calimero-registry` | Signing and publishing apps to the registry |
|
|
12
|
+
| `calimero-desktop` | `npx @calimero-network/agent-skills calimero-desktop` | Integrating apps with Calimero Desktop SSO |
|
|
13
|
+
| `calimero-node` | `npx @calimero-network/agent-skills calimero-node` | Node operators and meroctl scripting |
|
|
14
|
+
| `calimero-merobox` | `npx @calimero-network/agent-skills calimero-merobox` | Local multi-node dev environments and CI |
|
|
15
|
+
| `calimero-client-py` | `npx @calimero-network/agent-skills calimero-client-py` | Python client for node automation and backend services |
|
|
16
|
+
| `calimero-abi-codegen` | `npx @calimero-network/agent-skills calimero-abi-codegen` | Generate TypeScript clients from WASM ABI manifests |
|
|
17
|
+
|
|
18
|
+
## Auto-Detection
|
|
19
|
+
|
|
20
|
+
Skills should be loaded when the following are detected in the project:
|
|
21
|
+
|
|
22
|
+
| Signal | Load skill |
|
|
23
|
+
| --- | --- |
|
|
24
|
+
| `calimero-sdk` in `Cargo.toml` | `calimero-rust-sdk` |
|
|
25
|
+
| `@calimero-network/calimero-client` in `package.json` | `calimero-client-js` |
|
|
26
|
+
| `@calimero-network/mero-js` in `package.json` | `calimero-client-js` |
|
|
27
|
+
| `mero-sign` in any script or Makefile | `calimero-registry` |
|
|
28
|
+
| `calimero-registry` CLI usage | `calimero-registry` |
|
|
29
|
+
| `access_token` read from `window.location.hash` | `calimero-desktop` |
|
|
30
|
+
| `merobox` in `package.json` or `requirements.txt` | `calimero-merobox` |
|
|
31
|
+
| `calimero-client-py` in `requirements.txt` or `pyproject.toml` | `calimero-client-py` |
|
|
32
|
+
| `calimero-abi-codegen` or `abi.json` in project | `calimero-abi-codegen` |
|
|
33
|
+
|
|
34
|
+
## About Calimero
|
|
35
|
+
|
|
36
|
+
Calimero is a framework for distributed, peer-to-peer applications with automatic CRDT-based data synchronization, user-owned data, and verifiable off-chain computing.
|
|
37
|
+
|
|
38
|
+
Core concepts:
|
|
39
|
+
- **Context** — an isolated application instance with its own state, members, and storage
|
|
40
|
+
- **Application** — WASM code deployed to a node; each context runs one application
|
|
41
|
+
- **Node** (`merod`) — the runtime that hosts apps, syncs state, and exposes JSON-RPC/WebSocket
|
|
42
|
+
- **Identity** — root key → client keys per device; JWT tokens for API auth
|
|
43
|
+
- **CRDT state** — conflict-free replicated data; state lives on node storage, synced across context members
|
package/package.json
ADDED
|
@@ -0,0 +1,43 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "@calimero-network/agent-skills",
|
|
3
|
+
"version": "0.1.0",
|
|
4
|
+
"description": "AI agent skills for Calimero Network development — Rust SDK, JS client, registry publishing, desktop SSO, and more.",
|
|
5
|
+
"keywords": [
|
|
6
|
+
"calimero",
|
|
7
|
+
"agent-skills",
|
|
8
|
+
"ai",
|
|
9
|
+
"p2p",
|
|
10
|
+
"crdt",
|
|
11
|
+
"wasm",
|
|
12
|
+
"mero-sign",
|
|
13
|
+
"calimero-sdk"
|
|
14
|
+
],
|
|
15
|
+
"homepage": "https://github.com/calimero-network/agent-skills",
|
|
16
|
+
"bugs": {
|
|
17
|
+
"url": "https://github.com/calimero-network/agent-skills/issues"
|
|
18
|
+
},
|
|
19
|
+
"repository": {
|
|
20
|
+
"type": "git",
|
|
21
|
+
"url": "https://github.com/calimero-network/agent-skills.git"
|
|
22
|
+
},
|
|
23
|
+
"license": "MIT",
|
|
24
|
+
"bin": {
|
|
25
|
+
"calimero-skills": "./scripts/install.js"
|
|
26
|
+
},
|
|
27
|
+
"files": [
|
|
28
|
+
"skills/",
|
|
29
|
+
"SKILL.md",
|
|
30
|
+
"scripts/",
|
|
31
|
+
"README.md"
|
|
32
|
+
],
|
|
33
|
+
"scripts": {
|
|
34
|
+
"format": "prettier --write \"**/*.{md,json,js,ts}\"",
|
|
35
|
+
"format:check": "prettier --check \"**/*.{md,json,js,ts}\"",
|
|
36
|
+
"lint:md": "markdownlint-cli2 \"**/*.md\" \"!node_modules/**\"",
|
|
37
|
+
"test": "node scripts/test.js"
|
|
38
|
+
},
|
|
39
|
+
"devDependencies": {
|
|
40
|
+
"markdownlint-cli2": "^0.13.0",
|
|
41
|
+
"prettier": "^3.3.3"
|
|
42
|
+
}
|
|
43
|
+
}
|
|
@@ -0,0 +1,116 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
'use strict';
|
|
3
|
+
|
|
4
|
+
const fs = require('fs');
|
|
5
|
+
const path = require('path');
|
|
6
|
+
|
|
7
|
+
const SKILLS_DIR = path.join(__dirname, '..', 'skills');
|
|
8
|
+
const VALID_SKILLS = fs.readdirSync(SKILLS_DIR).filter((f) =>
|
|
9
|
+
fs.statSync(path.join(SKILLS_DIR, f)).isDirectory()
|
|
10
|
+
);
|
|
11
|
+
|
|
12
|
+
const TARGETS = {
|
|
13
|
+
claude: 'CLAUDE.md',
|
|
14
|
+
cursor: '.cursorrules',
|
|
15
|
+
copilot: '.github/copilot-instructions.md',
|
|
16
|
+
};
|
|
17
|
+
|
|
18
|
+
function parseArgs() {
|
|
19
|
+
const args = process.argv.slice(2);
|
|
20
|
+
const skill = args.find((a) => !a.startsWith('--'));
|
|
21
|
+
const target = args.includes('--cursor')
|
|
22
|
+
? 'cursor'
|
|
23
|
+
: args.includes('--copilot')
|
|
24
|
+
? 'copilot'
|
|
25
|
+
: 'claude';
|
|
26
|
+
const listOnly = args.includes('--list');
|
|
27
|
+
return { skill, target, listOnly };
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
function readSkillContent(skillName) {
|
|
31
|
+
const skillDir = path.join(SKILLS_DIR, skillName);
|
|
32
|
+
const parts = [];
|
|
33
|
+
|
|
34
|
+
// SKILL.md first
|
|
35
|
+
const skillMd = path.join(skillDir, 'SKILL.md');
|
|
36
|
+
if (fs.existsSync(skillMd)) {
|
|
37
|
+
parts.push(fs.readFileSync(skillMd, 'utf8').trim());
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
// references/
|
|
41
|
+
const refsDir = path.join(skillDir, 'references');
|
|
42
|
+
if (fs.existsSync(refsDir)) {
|
|
43
|
+
const refs = fs.readdirSync(refsDir).filter((f) => f.endsWith('.md'));
|
|
44
|
+
for (const ref of refs.sort()) {
|
|
45
|
+
parts.push(fs.readFileSync(path.join(refsDir, ref), 'utf8').trim());
|
|
46
|
+
}
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
// rules/
|
|
50
|
+
const rulesDir = path.join(skillDir, 'rules');
|
|
51
|
+
if (fs.existsSync(rulesDir)) {
|
|
52
|
+
const rules = fs.readdirSync(rulesDir).filter((f) => f.endsWith('.md'));
|
|
53
|
+
for (const rule of rules.sort()) {
|
|
54
|
+
parts.push(fs.readFileSync(path.join(rulesDir, rule), 'utf8').trim());
|
|
55
|
+
}
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
return parts.join('\n\n---\n\n');
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
function appendToFile(filePath, header, content) {
|
|
62
|
+
const marker = `<!-- calimero-skills:${header} -->`;
|
|
63
|
+
const block = `\n\n${marker}\n\n${content}\n\n${marker}:end`;
|
|
64
|
+
|
|
65
|
+
if (fs.existsSync(filePath)) {
|
|
66
|
+
const existing = fs.readFileSync(filePath, 'utf8');
|
|
67
|
+
// Replace existing block if present
|
|
68
|
+
const re = new RegExp(`${marker}[\\s\\S]*?${marker}:end`, 'g');
|
|
69
|
+
if (re.test(existing)) {
|
|
70
|
+
fs.writeFileSync(filePath, existing.replace(re, block.trim()));
|
|
71
|
+
return 'updated';
|
|
72
|
+
}
|
|
73
|
+
fs.appendFileSync(filePath, block);
|
|
74
|
+
return 'appended';
|
|
75
|
+
} else {
|
|
76
|
+
fs.writeFileSync(filePath, block.trim());
|
|
77
|
+
return 'created';
|
|
78
|
+
}
|
|
79
|
+
}
|
|
80
|
+
|
|
81
|
+
function main() {
|
|
82
|
+
const { skill, target, listOnly } = parseArgs();
|
|
83
|
+
|
|
84
|
+
if (listOnly || !skill) {
|
|
85
|
+
console.log('\nAvailable Calimero agent skills:\n');
|
|
86
|
+
for (const s of VALID_SKILLS) {
|
|
87
|
+
console.log(` ${s}`);
|
|
88
|
+
}
|
|
89
|
+
console.log('\nUsage:');
|
|
90
|
+
console.log(' npx @calimero-network/agent-skills <skill-name>');
|
|
91
|
+
console.log(' npx @calimero-network/agent-skills <skill-name> --cursor');
|
|
92
|
+
console.log(' npx @calimero-network/agent-skills <skill-name> --copilot');
|
|
93
|
+
console.log(' npx @calimero-network/agent-skills --list\n');
|
|
94
|
+
if (!listOnly) process.exit(1);
|
|
95
|
+
return;
|
|
96
|
+
}
|
|
97
|
+
|
|
98
|
+
if (!VALID_SKILLS.includes(skill)) {
|
|
99
|
+
console.error(`\nUnknown skill: "${skill}"`);
|
|
100
|
+
console.error(`Valid skills: ${VALID_SKILLS.join(', ')}\n`);
|
|
101
|
+
process.exit(1);
|
|
102
|
+
}
|
|
103
|
+
|
|
104
|
+
const content = readSkillContent(skill);
|
|
105
|
+
const targetFile = TARGETS[target];
|
|
106
|
+
|
|
107
|
+
// Ensure parent dir exists (e.g. .github/ for copilot)
|
|
108
|
+
const dir = path.dirname(path.resolve(targetFile));
|
|
109
|
+
if (!fs.existsSync(dir)) fs.mkdirSync(dir, { recursive: true });
|
|
110
|
+
|
|
111
|
+
const result = appendToFile(targetFile, skill, content);
|
|
112
|
+
console.log(`\n✓ Skill "${skill}" ${result} in ${targetFile}`);
|
|
113
|
+
console.log(` Target: ${target}\n`);
|
|
114
|
+
}
|
|
115
|
+
|
|
116
|
+
main();
|
package/scripts/test.js
ADDED
|
@@ -0,0 +1,67 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
'use strict';
|
|
3
|
+
|
|
4
|
+
const fs = require('fs');
|
|
5
|
+
const path = require('path');
|
|
6
|
+
|
|
7
|
+
const SKILLS_DIR = path.join(__dirname, '..', 'skills');
|
|
8
|
+
let passed = 0;
|
|
9
|
+
let failed = 0;
|
|
10
|
+
|
|
11
|
+
function assert(condition, message) {
|
|
12
|
+
if (condition) {
|
|
13
|
+
console.log(` ✓ ${message}`);
|
|
14
|
+
passed++;
|
|
15
|
+
} else {
|
|
16
|
+
console.error(` ✗ ${message}`);
|
|
17
|
+
failed++;
|
|
18
|
+
}
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
const skills = fs.readdirSync(SKILLS_DIR).filter((f) =>
|
|
22
|
+
fs.statSync(path.join(SKILLS_DIR, f)).isDirectory()
|
|
23
|
+
);
|
|
24
|
+
|
|
25
|
+
console.log(`\nChecking ${skills.length} skills...\n`);
|
|
26
|
+
|
|
27
|
+
for (const skill of skills) {
|
|
28
|
+
console.log(`[${skill}]`);
|
|
29
|
+
const skillDir = path.join(SKILLS_DIR, skill);
|
|
30
|
+
|
|
31
|
+
assert(
|
|
32
|
+
fs.existsSync(path.join(skillDir, 'SKILL.md')),
|
|
33
|
+
'SKILL.md exists'
|
|
34
|
+
);
|
|
35
|
+
assert(
|
|
36
|
+
fs.existsSync(path.join(skillDir, 'references')),
|
|
37
|
+
'references/ directory exists'
|
|
38
|
+
);
|
|
39
|
+
assert(
|
|
40
|
+
fs.existsSync(path.join(skillDir, 'rules')),
|
|
41
|
+
'rules/ directory exists'
|
|
42
|
+
);
|
|
43
|
+
|
|
44
|
+
const skillMd = path.join(skillDir, 'SKILL.md');
|
|
45
|
+
if (fs.existsSync(skillMd)) {
|
|
46
|
+
const content = fs.readFileSync(skillMd, 'utf8');
|
|
47
|
+
assert(content.length > 100, 'SKILL.md has meaningful content');
|
|
48
|
+
assert(content.includes('##'), 'SKILL.md has sections');
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
const refsDir = path.join(skillDir, 'references');
|
|
52
|
+
if (fs.existsSync(refsDir)) {
|
|
53
|
+
const refs = fs.readdirSync(refsDir).filter((f) => f.endsWith('.md'));
|
|
54
|
+
assert(refs.length > 0, `references/ has at least one file (found ${refs.length})`);
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
const rulesDir = path.join(skillDir, 'rules');
|
|
58
|
+
if (fs.existsSync(rulesDir)) {
|
|
59
|
+
const rules = fs.readdirSync(rulesDir).filter((f) => f.endsWith('.md'));
|
|
60
|
+
assert(rules.length > 0, `rules/ has at least one file (found ${rules.length})`);
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
console.log('');
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
console.log(`Results: ${passed} passed, ${failed} failed\n`);
|
|
67
|
+
if (failed > 0) process.exit(1);
|
|
@@ -0,0 +1,61 @@
|
|
|
1
|
+
# calimero-abi-codegen — Agent Instructions
|
|
2
|
+
|
|
3
|
+
You are helping a developer use **`calimero-abi-codegen`** to generate typed TypeScript
|
|
4
|
+
clients from a Calimero WASM application's ABI manifest.
|
|
5
|
+
|
|
6
|
+
## What it does
|
|
7
|
+
|
|
8
|
+
Takes an `abi.json` file (exported by the Calimero Rust SDK) and generates two files:
|
|
9
|
+
- `types.ts` — all TypeScript type definitions matching the app's Rust types
|
|
10
|
+
- `{ClientName}.ts` — a typed client class with methods for every app function
|
|
11
|
+
|
|
12
|
+
After codegen, frontend developers call app methods with full TypeScript type safety
|
|
13
|
+
instead of constructing raw JSON-RPC calls by hand.
|
|
14
|
+
|
|
15
|
+
## Install & run
|
|
16
|
+
|
|
17
|
+
```bash
|
|
18
|
+
# One-off (no install)
|
|
19
|
+
npx calimero-abi-codegen -i abi.json -o src/generated
|
|
20
|
+
|
|
21
|
+
# Or install globally
|
|
22
|
+
npm install -g @calimero-network/abi-codegen
|
|
23
|
+
calimero-abi-codegen -i abi.json -o src/generated
|
|
24
|
+
```
|
|
25
|
+
|
|
26
|
+
## CLI flags
|
|
27
|
+
|
|
28
|
+
| Flag | Default | Description |
|
|
29
|
+
| --- | --- | --- |
|
|
30
|
+
| `-i, --input <file>` | `abi.json` | Input ABI JSON file |
|
|
31
|
+
| `-o, --outDir <dir>` | `src` | Output directory |
|
|
32
|
+
| `--client-name <Name>` | `Client` | Class name for generated client |
|
|
33
|
+
| `--name-from <path>` | — | Derive class name from a file path (e.g. WASM file) |
|
|
34
|
+
| `--import-path <path>` | `@calimero-network/calimero-client` | Import path for base types |
|
|
35
|
+
| `--validate` | — | Validate ABI only, no code generation |
|
|
36
|
+
|
|
37
|
+
## Quick examples
|
|
38
|
+
|
|
39
|
+
```bash
|
|
40
|
+
# Basic
|
|
41
|
+
npx calimero-abi-codegen -i abi.json -o src/generated
|
|
42
|
+
|
|
43
|
+
# Custom class name
|
|
44
|
+
npx calimero-abi-codegen -i abi.json -o src/generated --client-name KvStoreClient
|
|
45
|
+
|
|
46
|
+
# Derive class name from WASM filename
|
|
47
|
+
npx calimero-abi-codegen -i abi.json -o src/generated --name-from kv_store.wasm
|
|
48
|
+
# → generates class KvStore
|
|
49
|
+
|
|
50
|
+
# Just validate the ABI (CI check)
|
|
51
|
+
npx calimero-abi-codegen --validate -i abi.json
|
|
52
|
+
```
|
|
53
|
+
|
|
54
|
+
## Critical: ABI schema version must be `wasm-abi/1`
|
|
55
|
+
|
|
56
|
+
The input JSON must have `"schema_version": "wasm-abi/1"`. Other versions are rejected.
|
|
57
|
+
|
|
58
|
+
## References
|
|
59
|
+
|
|
60
|
+
See `references/` for ABI format, generated output shape, and programmatic API.
|
|
61
|
+
See `rules/` for schema version and unique name requirements.
|
|
@@ -0,0 +1,105 @@
|
|
|
1
|
+
# ABI Manifest Format
|
|
2
|
+
|
|
3
|
+
The input `abi.json` follows the `wasm-abi/1` schema.
|
|
4
|
+
|
|
5
|
+
## Minimal valid ABI
|
|
6
|
+
|
|
7
|
+
```json
|
|
8
|
+
{
|
|
9
|
+
"schema_version": "wasm-abi/1",
|
|
10
|
+
"types": {},
|
|
11
|
+
"methods": [],
|
|
12
|
+
"events": []
|
|
13
|
+
}
|
|
14
|
+
```
|
|
15
|
+
|
|
16
|
+
## Full example — KV Store ABI
|
|
17
|
+
|
|
18
|
+
```json
|
|
19
|
+
{
|
|
20
|
+
"schema_version": "wasm-abi/1",
|
|
21
|
+
"types": {
|
|
22
|
+
"Entry": {
|
|
23
|
+
"kind": "record",
|
|
24
|
+
"fields": [
|
|
25
|
+
{ "name": "key", "type": { "kind": "string" } },
|
|
26
|
+
{ "name": "value", "type": { "kind": "string" } }
|
|
27
|
+
]
|
|
28
|
+
}
|
|
29
|
+
},
|
|
30
|
+
"methods": [
|
|
31
|
+
{
|
|
32
|
+
"name": "set",
|
|
33
|
+
"params": [
|
|
34
|
+
{ "name": "key", "type": { "kind": "string" } },
|
|
35
|
+
{ "name": "value", "type": { "kind": "string" } }
|
|
36
|
+
]
|
|
37
|
+
},
|
|
38
|
+
{
|
|
39
|
+
"name": "get",
|
|
40
|
+
"params": [
|
|
41
|
+
{ "name": "key", "type": { "kind": "string" } }
|
|
42
|
+
],
|
|
43
|
+
"returns": { "kind": "string" },
|
|
44
|
+
"returns_nullable": true
|
|
45
|
+
},
|
|
46
|
+
{
|
|
47
|
+
"name": "entries",
|
|
48
|
+
"params": [],
|
|
49
|
+
"returns": { "kind": "list", "items": { "$ref": "Entry" } }
|
|
50
|
+
}
|
|
51
|
+
],
|
|
52
|
+
"events": [
|
|
53
|
+
{
|
|
54
|
+
"name": "ItemSet",
|
|
55
|
+
"payload": { "$ref": "Entry" }
|
|
56
|
+
}
|
|
57
|
+
]
|
|
58
|
+
}
|
|
59
|
+
```
|
|
60
|
+
|
|
61
|
+
## Type reference forms
|
|
62
|
+
|
|
63
|
+
```json
|
|
64
|
+
{ "kind": "string" } // scalar
|
|
65
|
+
{ "kind": "bool" }
|
|
66
|
+
{ "kind": "u32" }
|
|
67
|
+
{ "kind": "u64" }
|
|
68
|
+
{ "kind": "bytes", "encoding": "hex" } // variable bytes
|
|
69
|
+
{ "$ref": "TypeName" } // reference to named type in types{}
|
|
70
|
+
{ "kind": "list", "items": { ... } } // array
|
|
71
|
+
{ "kind": "map", "key": { ... }, "value": { ... } } // map (key must be string)
|
|
72
|
+
{ "kind": "record", "fields": [...] } // inline struct
|
|
73
|
+
```
|
|
74
|
+
|
|
75
|
+
## Type definitions (`types` object)
|
|
76
|
+
|
|
77
|
+
```json
|
|
78
|
+
"types": {
|
|
79
|
+
"MyStruct": {
|
|
80
|
+
"kind": "record",
|
|
81
|
+
"fields": [
|
|
82
|
+
{ "name": "id", "type": { "kind": "u64" } },
|
|
83
|
+
{ "name": "name", "type": { "kind": "string" } },
|
|
84
|
+
{ "name": "tags", "type": { "kind": "list", "items": { "kind": "string" } } }
|
|
85
|
+
]
|
|
86
|
+
},
|
|
87
|
+
"Status": {
|
|
88
|
+
"kind": "variant",
|
|
89
|
+
"variants": [
|
|
90
|
+
{ "name": "Active" },
|
|
91
|
+
{ "name": "Inactive" },
|
|
92
|
+
{ "name": "Pending", "payload": { "kind": "string" } }
|
|
93
|
+
]
|
|
94
|
+
}
|
|
95
|
+
}
|
|
96
|
+
```
|
|
97
|
+
|
|
98
|
+
## Validation rules
|
|
99
|
+
|
|
100
|
+
- `schema_version` must be exactly `"wasm-abi/1"`
|
|
101
|
+
- No `$ref` pointing to a type not in `types{}`
|
|
102
|
+
- Map keys must be string type
|
|
103
|
+
- All method names must be unique
|
|
104
|
+
- All event names must be unique
|
|
105
|
+
- All type names must be unique
|