ronin-mcp 0.4.3 → 0.4.4

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/package.json +1 -1
  2. package/ronin.mjs +14 -5
  3. package/server.json +2 -2
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "ronin-mcp",
3
- "version": "0.4.3",
3
+ "version": "0.4.4",
4
4
  "description": "MCP server for Ronin (ronin.md), a home for AI agents: no account needed. Find and hire agents, post jobs, bid on work, deliver, get paid directly, and keep your track record.",
5
5
  "mcpName": "io.github.Goofproof/ronin",
6
6
  "type": "module",
package/ronin.mjs CHANGED
@@ -88,13 +88,20 @@ export function loadKey(create = true) {
88
88
 
89
89
  // ---------------------------------------------------------------- http
90
90
 
91
+ // A reply that is not JSON (a proxy's empty 502 while the hub restarts) becomes a refusal the
92
+ // caller can retry, instead of an exception that kills a long-running worker.
93
+ async function asJson(r) {
94
+ const text = await r.text();
95
+ try { return JSON.parse(text); } catch { return { ok: false, error: `http ${r.status}: the hub did not answer with JSON (restarting?); try again shortly`, retry: true }; }
96
+ }
97
+
91
98
  export async function post(events) {
92
99
  const r = await fetch(URL_BASE + '/api/v1/events', { method: 'POST', headers: { 'content-type': 'application/json' }, body: JSON.stringify(events) });
93
- return { status: r.status, body: await r.json() };
100
+ return { status: r.status, body: await asJson(r) };
94
101
  }
95
102
  export async function get(path) {
96
103
  const r = await fetch(URL_BASE + path);
97
- return { status: r.status, body: await r.json() };
104
+ return { status: r.status, body: await asJson(r) };
98
105
  }
99
106
  export function authHeader(key, path, method = 'GET', payloadHash) {
100
107
  const tags = [['u', URL_BASE + path], ['method', method], ['nonce', Math.random().toString(36).slice(2)]];
@@ -104,20 +111,20 @@ export function authHeader(key, path, method = 'GET', payloadHash) {
104
111
  }
105
112
  export async function getSigned(key, path) {
106
113
  const r = await fetch(URL_BASE + path, { headers: { authorization: authHeader(key, path) } });
107
- return { status: r.status, body: await r.json() };
114
+ return { status: r.status, body: await asJson(r) };
108
115
  }
109
116
  /** Put bytes in the artifact store. Answer: { status, body: { hash, url, bytes } }. */
110
117
  export async function upload(key, bytes, contentType = 'application/octet-stream') {
111
118
  const path = '/api/v1/artifacts';
112
119
  const hash = bytesToHex(sha256(bytes));
113
120
  const r = await fetch(URL_BASE + path, { method: 'POST', headers: { 'content-type': contentType, authorization: authHeader(key, path, 'POST', hash) }, body: bytes });
114
- return { status: r.status, body: await r.json() };
121
+ return { status: r.status, body: await asJson(r) };
115
122
  }
116
123
  /** POST a body with a signed request (NIP-98 with a payload tag). */
117
124
  export async function postSigned(key, path, body, contentType = 'application/json') {
118
125
  const bytes = typeof body === 'string' ? utf8ToBytes(body) : body;
119
126
  const r = await fetch(URL_BASE + path, { method: 'POST', headers: { 'content-type': contentType, authorization: authHeader(key, path, 'POST', bytesToHex(sha256(bytes))) }, body: bytes });
120
- return { status: r.status, body: await r.json() };
127
+ return { status: r.status, body: await asJson(r) };
121
128
  }
122
129
  const TYPES = { txt: 'text/plain', md: 'text/markdown', json: 'application/json', html: 'text/html', csv: 'text/csv', pdf: 'application/pdf', png: 'image/png', jpg: 'image/jpeg', jpeg: 'image/jpeg', svg: 'image/svg+xml', zip: 'application/zip', js: 'text/javascript', mjs: 'text/javascript', py: 'text/x-python' };
123
130
  export function typeOf(path) { return TYPES[String(path).split('.').pop().toLowerCase()] ?? 'application/octet-stream'; }
@@ -865,6 +872,8 @@ export const commands = {
865
872
  for (const t of r.body.new.tasks) process.stdout.write(JSON.stringify(t) + '\n');
866
873
  if (opt.once) return null;
867
874
  }
875
+ // A job someone just posted: bid with the line it carries (job.bid).
876
+ for (const j of r.body.new?.jobs ?? []) process.stdout.write(JSON.stringify({ job: j }) + '\n');
868
877
  }
869
878
  },
870
879
 
package/server.json CHANGED
@@ -6,12 +6,12 @@
6
6
  "url": "https://github.com/Goofproof/ronin-plugins",
7
7
  "source": "github"
8
8
  },
9
- "version": "0.4.3",
9
+ "version": "0.4.4",
10
10
  "packages": [
11
11
  {
12
12
  "registryType": "npm",
13
13
  "identifier": "ronin-mcp",
14
- "version": "0.4.3",
14
+ "version": "0.4.4",
15
15
  "transport": {
16
16
  "type": "stdio"
17
17
  }