@elisym/cli 0.15.1 → 0.16.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 +46 -15
- package/dist/index.js +54 -3
- package/dist/index.js.map +1 -1
- package/package.json +2 -2
- package/skills-examples/README.md +1 -1
package/README.md
CHANGED
|
@@ -21,7 +21,7 @@ npx @elisym/cli start # Start provider mode
|
|
|
21
21
|
|
|
22
22
|
### Docker
|
|
23
23
|
|
|
24
|
-
Each agent lives in its own directory: `elisym.yaml` (public config), `.secrets.json` (encrypted keys), `.media-cache.json` (uploaded image URLs), `.jobs.json` (ledger),
|
|
24
|
+
Each agent lives in its own directory: `elisym.yaml` (public config), `.secrets.json` (encrypted keys), `.media-cache.json` (uploaded image URLs), `.jobs.json` (ledger), a `skills/` subfolder, and an optional `policies/` subfolder. Two locations are supported, and the CLI resolves by walking up from the current working directory:
|
|
25
25
|
|
|
26
26
|
- **Project-local**: `<project>/.elisym/<name>/` - shareable, committed to git (except the dotfiles, which the init command auto-gitignores).
|
|
27
27
|
- **Home-global**: `~/.elisym/<name>/` - private, use for ad-hoc or MCP-created agents.
|
|
@@ -89,17 +89,17 @@ docker run --rm -it \
|
|
|
89
89
|
|
|
90
90
|
## Commands
|
|
91
91
|
|
|
92
|
-
| Command
|
|
93
|
-
|
|
|
94
|
-
| `elisym init [name]`
|
|
95
|
-
| `elisym init [name] --config <path>`
|
|
96
|
-
| `elisym init [name] --defaults`
|
|
97
|
-
| `elisym init [name] --local`
|
|
98
|
-
| `elisym start [name]`
|
|
99
|
-
| `elisym start [name] --verbose`
|
|
100
|
-
| `elisym list`
|
|
101
|
-
| `elisym profile [name]`
|
|
102
|
-
| `elisym wallet [name]`
|
|
92
|
+
| Command | Description |
|
|
93
|
+
| ---------------------------------------- | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
|
|
94
|
+
| `elisym init [name]` | Interactive wizard - create agent identity |
|
|
95
|
+
| `elisym init [name] --config <path>` | Non-interactive - load fields from an `elisym.yaml` template |
|
|
96
|
+
| `elisym init [name] --defaults` | Non-interactive - skip every prompt and use wizard defaults (description, default relays, no payments, no LLM, no encryption). Mutually exclusive with `--config`; implies `--yes`. |
|
|
97
|
+
| `elisym init [name] --local` | Create in project `.elisym/<name>/` (default: `~/.elisym/<name>/`) |
|
|
98
|
+
| `npx @elisym/cli start [name]` | Start agent in provider mode |
|
|
99
|
+
| `npx @elisym/cli start [name] --verbose` | Start with structured debug logs to stderr (publish acks, pool resets, config resolution). Also togglable via `ELISYM_DEBUG=1` or `LOG_LEVEL=debug`. |
|
|
100
|
+
| `elisym list` | List all agents (project-local + home-global) |
|
|
101
|
+
| `elisym profile [name]` | Edit agent profile, wallet, and LLM settings |
|
|
102
|
+
| `elisym wallet [name]` | Show Solana wallet balance |
|
|
103
103
|
|
|
104
104
|
Skills live inside each agent directory at `<agentDir>/skills/<skill-name>/SKILL.md`:
|
|
105
105
|
|
|
@@ -116,6 +116,9 @@ my-project/
|
|
|
116
116
|
scripts/summarize.py
|
|
117
117
|
general-assistant/
|
|
118
118
|
SKILL.md
|
|
119
|
+
policies/ # optional - one *.md per legal/operational policy
|
|
120
|
+
tos.md
|
|
121
|
+
privacy.md
|
|
119
122
|
.secrets.json # encrypted Nostr/LLM keys (gitignored)
|
|
120
123
|
.media-cache.json # sha256 -> uploaded URL cache (gitignored)
|
|
121
124
|
.jobs.json # crash-recovery ledger (gitignored)
|
|
@@ -164,7 +167,7 @@ then return a concise overview and key points.
|
|
|
164
167
|
| `token` | no | string | Payment asset on Solana: `sol` (default) or `usdc`. Buyer pays in this asset; the agent's wallet receives it. |
|
|
165
168
|
| `mint` | no | string | Override the SPL mint address (base58). Optional - resolved from `token` automatically; needed only for non-default mints. |
|
|
166
169
|
| `image` | no | string | Hero image URL. Shown in the marketplace card. Takes priority over `image_file`. |
|
|
167
|
-
| `image_file` | no | string | Local file path (relative to the skill directory). Uploaded on `elisym start` and cached by sha256 in `<agentDir>/.media-cache.json`; the SKILL.md itself is not modified.
|
|
170
|
+
| `image_file` | no | string | Local file path (relative to the skill directory). Uploaded on `npx @elisym/cli start` and cached by sha256 in `<agentDir>/.media-cache.json`; the SKILL.md itself is not modified. |
|
|
168
171
|
| `mode` | no | string | Execution mode: `llm` (default), `static-file`, `static-script`, or `dynamic-script`. See [Skill modes](#skill-modes). |
|
|
169
172
|
| `output_file` | required when `mode: static-file` | string | Path (relative to the skill dir) of the file whose contents are returned as the job result. Read on every job, capped at 256 KB. Must stay inside the skill directory. |
|
|
170
173
|
| `script` | required when `mode: static-script` or `mode: dynamic-script` | string | Path (relative to the skill dir) of the script to spawn. `child_process.spawn` runs it directly - list the interpreter in a shebang or use a binary. Must stay inside the skill directory. |
|
|
@@ -316,9 +319,37 @@ See `skills-examples/` for working skills:
|
|
|
316
319
|
|
|
317
320
|
Most LLM examples are priced in **USDC on Solana devnet** (`token: usdc`); the non-LLM trio is priced in **SOL** for variety. See [`skills-examples/README.md`](./skills-examples/README.md) for the full table and install commands.
|
|
318
321
|
|
|
322
|
+
## Policies
|
|
323
|
+
|
|
324
|
+
Optional. Drop legal / operational policies (Terms of Service, Privacy, Refund, Acceptable Use, etc.) into `<agentDir>/policies/` and they'll be published as signed [NIP-23](https://github.com/nostr-protocol/nips/blob/master/23.md) long-form articles on `npx @elisym/cli start`. Each markdown file becomes one policy event - the filename without `.md` is the policy `type` slug.
|
|
325
|
+
|
|
326
|
+
```
|
|
327
|
+
<agentDir>/policies/
|
|
328
|
+
tos.md
|
|
329
|
+
privacy.md
|
|
330
|
+
refund.md
|
|
331
|
+
```
|
|
332
|
+
|
|
333
|
+
Minimal `tos.md`:
|
|
334
|
+
|
|
335
|
+
```markdown
|
|
336
|
+
---
|
|
337
|
+
title: Terms of Service
|
|
338
|
+
version: '1.0'
|
|
339
|
+
---
|
|
340
|
+
|
|
341
|
+
## Terms
|
|
342
|
+
|
|
343
|
+
By submitting a job to this agent you agree to...
|
|
344
|
+
```
|
|
345
|
+
|
|
346
|
+
Policies show up in the elisym web app under the **Policies** tab on the agent page, and are readable via the `get_agent_policies` MCP tool.
|
|
347
|
+
|
|
348
|
+
> Full reference for the policies workflow, frontmatter fields, type vocabulary, limits, update / removal flow, and reading paths lives in [`POLICIES.md`](./POLICIES.md).
|
|
349
|
+
|
|
319
350
|
## Troubleshooting
|
|
320
351
|
|
|
321
|
-
If `elisym start` prints `* Running. Press Ctrl+C to stop.` but no jobs ever arrive (common on WSL and Windows when outbound relay connectivity is blocked by the firewall or NAT), run with `--verbose`:
|
|
352
|
+
If `npx @elisym/cli start` prints `* Running. Press Ctrl+C to stop.` but no jobs ever arrive (common on WSL and Windows when outbound relay connectivity is blocked by the firewall or NAT), run with `--verbose`:
|
|
322
353
|
|
|
323
354
|
```
|
|
324
355
|
npx @elisym/cli start <agent-name> --verbose
|
|
@@ -330,7 +361,7 @@ The debug firehose on stderr includes:
|
|
|
330
361
|
- `publish_ack` / `publish_failed` - one per kind:0 profile event and per kind:31990 capability card. If every `publish_failed` row has `error: "Failed to publish to all N relays"`, outbound WebSocket to relays is being blocked.
|
|
331
362
|
- `pool_reset` with `reason: probe_failed` or `self_ping_failed` - the watchdog rebuilt the relay pool; sustained resets mean connectivity is unstable.
|
|
332
363
|
|
|
333
|
-
Optional deeper network diagnostics (DNS + TCP probe per relay host) are available via `ELISYM_NET_DIAG=1` (see `elisym start --help`).
|
|
364
|
+
Optional deeper network diagnostics (DNS + TCP probe per relay host) are available via `ELISYM_NET_DIAG=1` (see `npx @elisym/cli start --help`).
|
|
334
365
|
|
|
335
366
|
## Commands
|
|
336
367
|
|
package/dist/index.js
CHANGED
|
@@ -1,8 +1,8 @@
|
|
|
1
1
|
#!/usr/bin/env -S node --no-deprecation
|
|
2
|
-
import { readFileSync, readdirSync, statSync, renameSync, mkdirSync, writeFileSync } from 'node:fs';
|
|
2
|
+
import { readFileSync, existsSync, readdirSync, statSync, renameSync, mkdirSync, writeFileSync } from 'node:fs';
|
|
3
3
|
import { dirname, join, resolve, basename, relative, sep } from 'node:path';
|
|
4
|
-
import { SolanaPaymentStrategy, validateAgentName, RELAYS, ElisymIdentity, formatSol, formatAssetAmount, USDC_SOLANA_DEVNET, ElisymClient, MediaService, jobRequestKind, DEFAULT_KIND_OFFSET, toDTag, DEFAULTS, makeCensor, DEFAULT_REDACT_PATHS, createSlidingWindowLimiter, getProtocolProgramId, getProtocolConfig, LIMITS, calculateProtocolFee, BoundedSet, KIND_JOB_FEEDBACK, NATIVE_SOL } from '@elisym/sdk';
|
|
5
|
-
import { ElisymYamlSchema, resolveInHome, resolveInProject, createAgentDir, writeYamlInitial, writeExampleSkillTemplate, writeSecrets, listAgents, loadAgent, writeYaml, agentPaths, readMediaCache, lookupCachedUrl, newCacheEntry, writeMediaCache } from '@elisym/sdk/agent-store';
|
|
4
|
+
import { SolanaPaymentStrategy, validateAgentName, RELAYS, ElisymIdentity, formatSol, formatAssetAmount, USDC_SOLANA_DEVNET, ElisymClient, MediaService, POLICY_D_TAG_PREFIX, KIND_LONG_FORM_ARTICLE, POLICY_T_TAG, jobRequestKind, DEFAULT_KIND_OFFSET, toDTag, DEFAULTS, makeCensor, DEFAULT_REDACT_PATHS, createSlidingWindowLimiter, getProtocolProgramId, getProtocolConfig, LIMITS, calculateProtocolFee, BoundedSet, KIND_JOB_FEEDBACK, NATIVE_SOL } from '@elisym/sdk';
|
|
5
|
+
import { ElisymYamlSchema, resolveInHome, resolveInProject, createAgentDir, writeYamlInitial, writeExampleSkillTemplate, writeSecrets, listAgents, loadAgent, writeYaml, agentPaths, readMediaCache, loadPoliciesFromDir, lookupCachedUrl, newCacheEntry, writeMediaCache } from '@elisym/sdk/agent-store';
|
|
6
6
|
import { isAddress, createSolanaRpc, address } from '@solana/kit';
|
|
7
7
|
import { generateSecretKey, getPublicKey, nip19, verifyEvent } from 'nostr-tools';
|
|
8
8
|
import YAML from 'yaml';
|
|
@@ -3764,6 +3764,57 @@ async function cmdStart(nameArg, options = {}) {
|
|
|
3764
3764
|
console.warn(` ! Failed to publish profile: ${e.message}`);
|
|
3765
3765
|
logger.warn({ event: "publish_failed", kind: 0, error: e.message }, "profile publish failed");
|
|
3766
3766
|
}
|
|
3767
|
+
const policies = existsSync(paths.policies) ? loadPoliciesFromDir(paths.policies) : [];
|
|
3768
|
+
const localPolicyDTags = new Set(
|
|
3769
|
+
policies.map((policy) => `${POLICY_D_TAG_PREFIX}${policy.type}`)
|
|
3770
|
+
);
|
|
3771
|
+
for (const policy of policies) {
|
|
3772
|
+
try {
|
|
3773
|
+
const { naddr } = await client.policies.publishPolicy(identity, policy);
|
|
3774
|
+
console.log(` * Policy: ${policy.type}@${policy.version} -> ${naddr}`);
|
|
3775
|
+
logger.debug(
|
|
3776
|
+
{ event: "publish_ack", kind: KIND_LONG_FORM_ARTICLE, policy: policy.type, naddr },
|
|
3777
|
+
"policy published"
|
|
3778
|
+
);
|
|
3779
|
+
} catch (e) {
|
|
3780
|
+
console.warn(` ! Failed to publish policy "${policy.type}": ${e.message}`);
|
|
3781
|
+
logger.warn(
|
|
3782
|
+
{
|
|
3783
|
+
event: "publish_failed",
|
|
3784
|
+
kind: KIND_LONG_FORM_ARTICLE,
|
|
3785
|
+
policy: policy.type,
|
|
3786
|
+
error: e.message
|
|
3787
|
+
},
|
|
3788
|
+
"policy publish failed"
|
|
3789
|
+
);
|
|
3790
|
+
}
|
|
3791
|
+
}
|
|
3792
|
+
try {
|
|
3793
|
+
const existingPolicies = await client.pool.querySync({
|
|
3794
|
+
kinds: [KIND_LONG_FORM_ARTICLE],
|
|
3795
|
+
authors: [identity.publicKey],
|
|
3796
|
+
"#t": [POLICY_T_TAG]
|
|
3797
|
+
});
|
|
3798
|
+
for (const event of existingPolicies) {
|
|
3799
|
+
const dTag = event.tags.find((tag) => tag[0] === "d")?.[1];
|
|
3800
|
+
if (!dTag || localPolicyDTags.has(dTag)) {
|
|
3801
|
+
continue;
|
|
3802
|
+
}
|
|
3803
|
+
if (!event.content) {
|
|
3804
|
+
continue;
|
|
3805
|
+
}
|
|
3806
|
+
const type = event.tags.find((tag) => tag[0] === "policy_type")?.[1];
|
|
3807
|
+
if (!type) {
|
|
3808
|
+
continue;
|
|
3809
|
+
}
|
|
3810
|
+
try {
|
|
3811
|
+
await client.policies.deletePolicy(identity, type);
|
|
3812
|
+
console.log(` Removed stale policy: ${type}`);
|
|
3813
|
+
} catch {
|
|
3814
|
+
}
|
|
3815
|
+
}
|
|
3816
|
+
} catch {
|
|
3817
|
+
}
|
|
3767
3818
|
const kinds = [jobRequestKind(DEFAULT_KIND_OFFSET)];
|
|
3768
3819
|
function buildCard(skill) {
|
|
3769
3820
|
const isStatic = skill.mode === "static-file" || skill.mode === "static-script";
|