minia2a-skill 1.3.7 → 1.3.8

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 (2) hide show
  1. package/cli/minia2a +67 -6
  2. package/package.json +1 -1
package/cli/minia2a CHANGED
@@ -32,6 +32,67 @@ function json(data) {
32
32
  console.log(JSON.stringify(data));
33
33
  }
34
34
 
35
+ // ----- agent identity -----
36
+ // Sent on first-party requests so the gateway can count distinct agents; the
37
+ // server stores only HMAC(secret, id), never the raw value. Identity is
38
+ // per-machine, not per-process — a per-process id would count every invocation
39
+ // as a new agent and inflate the adoption metric it feeds.
40
+ const os = require('os');
41
+ const fs = require('fs');
42
+ const path = require('path');
43
+ let _agentIdResolved = false;
44
+ let _agentIdCache = null;
45
+
46
+ function agentId() {
47
+ if (_agentIdResolved) return _agentIdCache;
48
+ _agentIdResolved = true;
49
+ const fromEnv = process.env.MINIA2A_AGENT_ID;
50
+ if (fromEnv) return (_agentIdCache = fromEnv);
51
+ // Two locations exist across our published clients: the `minia2a` package reads
52
+ // ~/.minia2a-agent-id (the path the gateway's adoption.go names) and
53
+ // `minia2a-cli` reads ~/.minia2a/agent-id. Read both, in that order, so a
54
+ // machine that already has an id from either client keeps one identity instead
55
+ // of being counted twice; create the gateway-documented one.
56
+ const candidates = [
57
+ path.join(os.homedir(), '.minia2a-agent-id'),
58
+ path.join(os.homedir(), '.minia2a', 'agent-id'),
59
+ ];
60
+ for (const file of candidates) {
61
+ try {
62
+ const existing = fs.readFileSync(file, 'utf8').trim();
63
+ if (existing) return (_agentIdCache = existing);
64
+ } catch (e) { /* not created yet — fall through to the next candidate */ }
65
+ }
66
+ const id = 'agent:' + require('crypto').randomUUID();
67
+ try {
68
+ fs.writeFileSync(candidates[0], id, { mode: 0o600 });
69
+ return (_agentIdCache = id);
70
+ } catch (e) {
71
+ return (_agentIdCache = null);
72
+ }
73
+ }
74
+
75
+ // The id identifies us to our own gateway. A catalog entry can point off-domain
76
+ // (the external-api category), so the header is gated on the host: a stable
77
+ // per-machine identifier must not travel to a third party.
78
+ function isFirstParty(url) {
79
+ try {
80
+ const h = new URL(url).hostname;
81
+ return h === 'minia2a.uk' || h.endsWith('.minia2a.uk');
82
+ } catch (e) {
83
+ return false;
84
+ }
85
+ }
86
+
87
+ function identityHeaders(url) {
88
+ const id = isFirstParty(url) ? agentId() : null;
89
+ return id ? { 'X-Agent-ID': id } : {};
90
+ }
91
+
92
+ function apiHeaders(url, extra) {
93
+ return { ...identityHeaders(url), ...(extra || {}) };
94
+ }
95
+
35
96
  // ----- argument parsing -----
36
97
  const argv = process.argv.slice(2);
37
98
  const cmd = argv[0];
@@ -60,7 +121,7 @@ async function discover() {
60
121
  if (category) params.set('category', category);
61
122
  if (sort) params.set('sort', sort);
62
123
  try {
63
- const r = await fetch(`${API}/api/services?${params}`);
124
+ const r = await fetch(`${API}/api/services?${params}`, { headers: apiHeaders(`${API}/api/services`) });
64
125
  const d = await r.json();
65
126
  json(d);
66
127
  if (!r.ok) process.exit(3);
@@ -71,7 +132,7 @@ async function discover() {
71
132
 
72
133
  async function meta() {
73
134
  try {
74
- const r = await fetch(`${API}/.well-known/x402`);
135
+ const r = await fetch(`${API}/.well-known/x402`, { headers: apiHeaders(`${API}/.well-known/x402`) });
75
136
  const d = await r.json();
76
137
  json(d);
77
138
  if (!r.ok) process.exit(3);
@@ -102,7 +163,7 @@ async function register() {
102
163
  try {
103
164
  const r = await fetch(`${API}/api/v1/register-simple`, {
104
165
  method: 'POST',
105
- headers: { 'Content-Type': 'application/json' },
166
+ headers: apiHeaders(`${API}/api/v1/register-simple`, { 'Content-Type': 'application/json' }),
106
167
  body: JSON.stringify(body)
107
168
  });
108
169
  const d = await r.json();
@@ -166,7 +227,7 @@ async function publish() {
166
227
  try {
167
228
  const r = await fetch(`${API}/api/v1/publish-service`, {
168
229
  method: 'POST',
169
- headers: { 'Content-Type': 'application/json' },
230
+ headers: apiHeaders(`${API}/api/v1/publish-service`, { 'Content-Type': 'application/json' }),
170
231
  body: JSON.stringify(body)
171
232
  });
172
233
  const d = await r.json();
@@ -195,7 +256,7 @@ async function call(id) {
195
256
  // Resolve the service endpoint
196
257
  let svc;
197
258
  try {
198
- const r = await fetch(`${API}/api/services/${encodeURIComponent(id)}`);
259
+ const r = await fetch(`${API}/api/services/${encodeURIComponent(id)}`, { headers: apiHeaders(`${API}/api/services`) });
199
260
  if (!r.ok) bail(`Service not found: ${id}`, 3);
200
261
  svc = await r.json();
201
262
  } catch (e) {
@@ -230,7 +291,7 @@ async function call(id) {
230
291
  }
231
292
 
232
293
  try {
233
- const opts = { headers: { 'User-Agent': 'minia2a-skill/1.x', ...trialHeaders } };
294
+ const opts = { headers: apiHeaders(url.toString(), { 'User-Agent': 'minia2a-skill/1.x', ...trialHeaders }) };
234
295
  let r;
235
296
  if (input !== undefined) {
236
297
  opts.method = 'POST';
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "minia2a-skill",
3
- "version": "1.3.7",
3
+ "version": "1.3.8",
4
4
  "description": "Agent skill for minia2a.uk — 1,680+ x402 services. AI agents earn USDC. 5 free trial calls. Zero-dep CLI. Try: npm i -g minia2a-cli.",
5
5
  "bin": {
6
6
  "minia2a": "./cli/minia2a"