minia2a-skill 1.2.1 → 1.3.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.
Files changed (3) hide show
  1. package/README.md +6 -0
  2. package/cli/minia2a +76 -1
  3. package/package.json +1 -1
package/README.md CHANGED
@@ -71,10 +71,16 @@ Every call is priced in the 402 response. The buyer pays USDC (or spends free cr
71
71
  minia2a discover [query] [--category cat] [--sort volume|price]
72
72
  minia2a meta
73
73
  minia2a register --name <n> --wallet <0x...> --signature <0x...>
74
+ minia2a publish --name <n> --endpoint <url> --price <cents> --description <text> \
75
+ [--category tools|premium|defi|data] --wallet <0x...> --signature <0x...>
74
76
  minia2a call <id> --wallet <0x...> [--input '{}'] [--probe]
75
77
  minia2a help
76
78
  ```
77
79
 
80
+ `register` is the **buyer** side (it provisions free credits). `publish` is the
81
+ **seller** side (it lists your API for pay-per-call). They are different endpoints
82
+ and sign different messages — registering does not create a listing.
83
+
78
84
  All commands output JSON. Exit code 0 = success. `--probe` returns the 402 payment JSON without consuming credits.
79
85
 
80
86
  ## Agent Wrappers
package/cli/minia2a CHANGED
@@ -12,6 +12,8 @@ Usage:
12
12
  minia2a discover [query] [--category <cat>] [--sort volume|price]
13
13
  minia2a meta
14
14
  minia2a register --name <n> --wallet <0x...> --signature <0x...>
15
+ minia2a publish --name <n> --endpoint <url> --price <cents> --description <text>
16
+ [--category <cat>] --wallet <0x...> --signature <0x...>
15
17
  minia2a call <service-id> --wallet <0x...> [--input <json>] [--probe]
16
18
  minia2a help [topic]
17
19
 
@@ -110,6 +112,75 @@ async function register() {
110
112
  }
111
113
  }
112
114
 
115
+ // Seller path. `register` above is BUYER-side (it provisions credits, not a listing) —
116
+ // publishing a service is a different endpoint with a different signed message.
117
+ const CATEGORIES = ['tools', 'premium', 'defi', 'data'];
118
+
119
+ async function publish() {
120
+ const name = flag('name');
121
+ const endpoint = flag('endpoint');
122
+ const price = flag('price');
123
+ const wallet = flag('wallet');
124
+ const signature = flag('signature');
125
+ let category = flag('category');
126
+
127
+ if (!name || name === true) bail('--name <name> required');
128
+ if (!endpoint || endpoint === true) bail('--endpoint <https://...> required');
129
+ if (!wallet || wallet === true) bail('--wallet <0x...> required (revenue settles here)');
130
+
131
+ if (!/^https?:\/\//i.test(endpoint)) bail('--endpoint must be an absolute http(s) URL');
132
+
133
+ // Rejected server-side anyway (SSRF guard) — fail early with a clearer reason.
134
+ if (/^https?:\/\/(localhost|127\.|10\.|192\.168\.|169\.254\.|\[::1\])/i.test(endpoint)) {
135
+ bail('--endpoint must be publicly reachable; internal/loopback addresses are rejected');
136
+ }
137
+
138
+ const priceCents = Number(price);
139
+ if (!Number.isInteger(priceCents) || priceCents < 1 || priceCents > 10000) {
140
+ bail('--price <cents> required: integer 1–10000 (1 = $0.01, 10000 = $100.00)');
141
+ }
142
+
143
+ // Server enforces a 20-char minimum; catch it here so the failure is legible.
144
+ const description = flag('description');
145
+ if (!description || description === true || String(description).length < 20) {
146
+ bail('--description <text> required: at least 20 characters (buyers see this in the catalog)');
147
+ }
148
+
149
+ if (!category || category === true) category = 'tools';
150
+ if (!CATEGORIES.includes(category)) {
151
+ bail(`--category must be one of: ${CATEGORIES.join(', ')}`);
152
+ }
153
+
154
+ if (!signature || signature === true) {
155
+ // Same contract as register: the CLI never holds your key.
156
+ console.error('A signature is required. Sign this exact message with your wallet (EIP-191 personal_sign):\n');
157
+ console.error(` minia2a publish: ${wallet}\n`);
158
+ console.error('Then re-run with --signature <0x...>:\n');
159
+ console.error(` minia2a publish --name "${name}" --endpoint "${endpoint}" --price ${priceCents} --wallet "${wallet}" --signature "0xYOUR_SIGNATURE"\n`);
160
+ console.error('(cast example: cast wallet sign --data 0x... "minia2a publish: <wallet>")');
161
+ process.exit(1);
162
+ }
163
+
164
+ const body = { name, endpoint, price_cents: priceCents, category, description, wallet, signature };
165
+ try {
166
+ const r = await fetch(`${API}/api/v1/publish-service`, {
167
+ method: 'POST',
168
+ headers: { 'Content-Type': 'application/json' },
169
+ body: JSON.stringify(body)
170
+ });
171
+ const d = await r.json();
172
+ json(d);
173
+ if (!r.ok) process.exit(3);
174
+ // The catalog does not round-trip an HTTP method yet, so POST-only endpoints
175
+ // get called with GET by generic clients. Warn rather than let it fail silently.
176
+ console.error('\nPublished. Note: the catalog does not yet record an HTTP method —');
177
+ console.error('callers default to GET. If your endpoint requires POST, state that in');
178
+ console.error('the service description until method round-trip ships.');
179
+ } catch (e) {
180
+ bail(`Cannot reach marketplace: ${e.message}`, 3);
181
+ }
182
+ }
183
+
113
184
  async function call(id) {
114
185
  if (!id) bail('Usage: minia2a call <service-id> --wallet <0x...> [--input <json>] [--probe]');
115
186
  const wallet = flag('wallet');
@@ -169,7 +240,8 @@ async function help() {
169
240
  console.error(`minia2a help: ${topic}\n`);
170
241
  console.error('The full machine-readable guide lives at https://minia2a.uk/AGENTS.md');
171
242
  console.error('Quick reference:');
172
- console.error(' register — POST /api/v1/register-simple {name, wallet, signature} → 500 free credits');
243
+ console.error(' register — POST /api/v1/register-simple {name, wallet, signature} → 500 free credits (BUYER side)');
244
+ console.error(' publish — POST /api/v1/publish-service {name, endpoint, price_cents, category, wallet, signature} (SELLER side)');
173
245
  console.error(' call — GET <service-endpoint>?wallet=0x... (credits decrement)');
174
246
  console.error(' probe — append ?probe=1 to any endpoint → HTTP 402 with payment JSON (free)');
175
247
  return;
@@ -189,6 +261,9 @@ async function help() {
189
261
  case 'info':
190
262
  case 'stats':
191
263
  return await meta();
264
+ case 'publish':
265
+ case 'sell':
266
+ return await publish();
192
267
  case 'register':
193
268
  case 'reg':
194
269
  return await register();
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "minia2a-skill",
3
- "version": "1.2.1",
3
+ "version": "1.3.0",
4
4
  "description": "Agent skill for minia2a.uk — 1,600+ x402 services. AI agents earn USDC. 500 free credits. Zero-dep CLI. Try: npm i -g minia2a-cli.",
5
5
  "bin": {
6
6
  "minia2a": "./cli/minia2a"