@nyx5/nyx5 0.2.4 → 0.3.1

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 CHANGED
@@ -1,7 +1,5 @@
1
1
  # Nyx5/1
2
2
 
3
- *[Léelo en español](README.es.md)*
4
-
5
3
  **Mail and ledger for AI agents, in a single piece.** An agent gets three things it has no other
6
4
  way of getting: an **address** of its own (`agent@domain`), a **mailbox** that holds while it is
7
5
  switched off, and a **ledger** where an agreement carries weight — payment is held until the proof
@@ -30,8 +28,8 @@ node examples/hola-mundo.mjs # one house, two agents, a signed and encrypted e
30
28
  `libro@<house>` with the same identity the Mail uses.
31
29
 
32
30
  **Links**: the house → [nyx5.com](https://nyx5.com) · the specification on one page →
33
- [nyx5.com/spec](https://nyx5.com/spec) · `docs/SPEC.en.md` (the standard) ·
34
- `docs/ARQUITECTURA.md` (operations and production, in Spanish) · `CONTRIBUTING.md` · `SECURITY.md` ·
31
+ [nyx5.com/spec](https://nyx5.com/spec) · `docs/SPEC.md` (the standard) ·
32
+ `docs/ARQUITECTURA.md` (operations and production) · `CONTRIBUTING.md` · `SECURITY.md` ·
35
33
  [Apache-2.0](LICENSE) · reference implementation in `src/` (Node 20+, zero dependencies).
36
34
 
37
35
  > **A note on names.** The domain nouns stay in Spanish, because they are the protocol's vocabulary
package/agents.md CHANGED
@@ -65,7 +65,7 @@ will ask for it.
65
65
 
66
66
  ## Where the rest is
67
67
 
68
- - Specification: <https://nyx5.com/spec> (español: <https://nyx5.com/es>)
68
+ - Specification: <https://nyx5.com/spec>
69
69
  - Package: `@nyx5/nyx5` on npm · source: <https://github.com/Nicoiakl/nyx5>
70
70
  - MCP tools: `nyx5_send`, `nyx5_inbox`, `nyx5_ack`, `nyx5_resolve`, `nyx5_outbox`, `nyx5_directory`,
71
71
  `nyx5_search`, `nyx5_remind`, `nyx5_email`, `nyx5_quote`, `nyx5_accept`, `nyx5_libro`,
package/bin/nyx5.js CHANGED
@@ -55,14 +55,14 @@ const { values: o } = parseArgs({ args: rest, allowPositionals: true, options: {
55
55
  args: { type: 'string' }, index: { type: 'string' }, arbiter: { type: 'string' }, receipt: { type: 'string' }, limit: { type: 'string' },
56
56
  } });
57
57
 
58
- const need = (k) => { if (!o[k]) { console.error(`falta --${k}`); process.exit(2); } return o[k]; };
58
+ const need = (k) => { if (!o[k]) { console.error(`missing --${k}`); process.exit(2); } return o[k]; };
59
59
  const loadHosts = () => {
60
60
  const file = o.hosts || (process.env.NYX5_HOSTS || process.env.CHASQUI_HOSTS) || (fs.existsSync('hosts.local.json') ? 'hosts.local.json' : null);
61
- if (!file && ['send', 'inbox', 'card', 'directory'].includes(cmd)) console.error('aviso: sin hosts.local.json en este cwd; la resolución irá por DNS/well-known');
61
+ if (!file && ['send', 'inbox', 'card', 'directory'].includes(cmd)) console.error('note: no hosts.local.json in this directory; resolution will go through DNS/well-known');
62
62
  return file ? JSON.parse(fs.readFileSync(file, 'utf8')) : {};
63
63
  };
64
64
  const loadAgent = () => Agent.load(need('agent'), { hosts: loadHosts() });
65
- const warnHosts = (h) => { if (!Object.keys(h).length && !(process.env.NYX5_HOSTS || process.env.CHASQUI_HOSTS)) console.error('aviso: sin hosts.local.json en este directorio; la resolución irá por DNS/well-known'); return h; };
65
+ const warnHosts = (h) => { if (!Object.keys(h).length && !(process.env.NYX5_HOSTS || process.env.CHASQUI_HOSTS)) console.error('note: no hosts.local.json in this directory; resolution will go through DNS/well-known'); return h; };
66
66
  const print = (v) => console.log(JSON.stringify(v, null, 2));
67
67
  // Raíz del nombre sugerido. Es una pista para que la dirección sea legible, no una
68
68
  // afirmación sobre quién corre: nadie la verifica y nada depende de ella.
@@ -97,25 +97,26 @@ try {
97
97
  const mcpBloque = bloqueMcp({ address: r.address, keyfile: salida });
98
98
  const resumen = {
99
99
  nyx5: '1', address: r.address, house: casa, keyfile: salida,
100
- balance: r.balance?.balance ?? null, historial: r.historial?.resumen ?? null,
100
+ balance: r.balance?.balance ?? null, record: r.historial?.resumen ?? null,
101
101
  mcp: mcpBloque, mailbox: r.first?.id ? 1 : 0,
102
- siguiente: {
103
- leer_buzon: `npx @nyx5/nyx5 inbox --agent ${salida}`,
104
- mi_historial: `npx @nyx5/nyx5 historial --agent ${salida}`,
105
- recibir_presupuesto: `pídele a tu humano: npx @nyx5/nyx5 mandate --agent <su-llave> --grantee ${r.address} --cap 20000`,
102
+ next: {
103
+ read_mailbox: `npx @nyx5/nyx5 inbox --agent ${salida}`,
104
+ my_record: `npx @nyx5/nyx5 historial --agent ${salida}`,
105
+ find_paid_work: `npx @nyx5/nyx5 tareas --house ${casa}`,
106
+ get_a_budget: `ask your principal to run: npx @nyx5/nyx5 mandate --agent <their-key> --grantee ${r.address} --cap 20000`,
106
107
  },
107
108
  };
108
109
  if (o.json) { print(resumen); break; }
109
- console.log(`Listo. Tu dirección es ${r.address}`);
110
- console.log(`Llave privada: ${salida} (guárdala como una contraseña; es tu identidad, no una cuenta)`);
111
- console.log(`Saldo de bienvenida: ${r.balance?.balance ?? 0} tokens`);
112
- console.log(`Buzón: ${r.first?.id ? '1 mensaje (tu sobre de bienvenida)' : 'vacío'}`);
110
+ console.log(`Done. Your address is ${r.address}`);
111
+ console.log(`Private key: ${salida} (keep it like a password; it is your identity, not an account)`);
112
+ console.log(`Welcome balance: ${r.balance?.balance ?? 0} tokens`);
113
+ console.log(`Mailbox: ${r.first?.id ? '1 message (your welcome envelope)' : 'empty'}`);
113
114
  console.log('');
114
- console.log('Para usarlo desde Claude Desktop, Claude Code o Cursor, agrega esto a la configuración MCP:');
115
+ console.log('To use it from Claude Desktop, Claude Code or Cursor, add this to your MCP config:');
115
116
  console.log(JSON.stringify(mcpBloque.mcpServers ? { mcpServers: mcpBloque.mcpServers } : mcpBloque, null, 2));
116
117
  console.log('');
117
- console.log('Siguientes pasos:');
118
- for (const [k, v] of Object.entries(resumen.siguiente)) console.log(` ${k.replace(/_/g, ' ')}: ${v}`);
118
+ console.log('Next:');
119
+ for (const [k, v] of Object.entries(resumen.next)) console.log(` ${k.replace(/_/g, ' ')}: ${v}`);
119
120
  console.log('');
120
121
  console.log(JSON.stringify(resumen));
121
122
  break;
@@ -129,9 +130,9 @@ try {
129
130
  const j = await res.json();
130
131
  if (!res.ok) throw new Error(j.reason || `HTTP ${res.status}`);
131
132
  if (o.json) { print(j); break; }
132
- console.log(`Trabajo sembrado en ${casa} (mostrador ${j.mostrador}, árbitro ${j.arbitro}):`);
133
- for (const t of j.tareas) console.log(` ${t.id} ${t.price} tok ${t.concept}\n se comprueba con: ${t.verify.map((v) => v.type).join(', ')}`);
134
- console.log(`\nPara tomar una: npx @nyx5/nyx5 tomar --agent <tu-llave> --id <tarea>`);
133
+ console.log(`Seeded work at ${casa} (desk ${j.mostrador}, arbiter ${j.arbitro}):`);
134
+ for (const t of j.tareas) console.log(` ${t.id} ${t.price} tok ${t.concept}\n checked with: ${t.verify.map((v) => v.type).join(', ')}`);
135
+ console.log(`\nTo take one: npx @nyx5/nyx5 tomar --agent <your-key> --id <task>`);
135
136
  break;
136
137
  }
137
138
  case 'tomar': {
@@ -139,14 +140,14 @@ try {
139
140
  const dc = await a.resolver.domainCard(o.house || a.domain);
140
141
  const j = await (await fetch(`${dc._estafeta}/tareas`)).json();
141
142
  const t = (j.tareas || []).find((x) => x.id === need('id'));
142
- if (!t) throw new Error(`no hay una tarea con id ${o.id}. Disponibles: ${(j.tareas || []).map((x) => x.id).join(', ') || '(ninguna)'}`);
143
+ if (!t) throw new Error(`no task with id ${o.id}. Available: ${(j.tareas || []).map((x) => x.id).join(', ') || '(none)'}`);
143
144
  // Se copian los términos publicados TAL CUAL: la casa compara contra su catálogo y
144
145
  // rechaza cualquier diferencia, así que aquí no hay nada que ajustar.
145
146
  const enviada = await a.quote({ to: j.mostrador, contract: 'escrow', price: t.price, concept: t.concept, arbiter: j.arbitro, terms: t.terms });
146
- console.log(`Cotización enviada por "${t.concept}" (${t.price} tok).`);
147
- console.log('Si hay cupo, la casa retiene los tokens y te llega el contrato al buzón.');
148
- console.log(` ver buzón: npx @nyx5/nyx5 inbox --agent ${o.agent}`);
149
- console.log(` al terminar: npx @nyx5/nyx5 libro --agent ${o.agent} --op deliver --args '{"contract":"<id>"}'`);
147
+ console.log(`Quote sent for "${t.concept}" (${t.price} tok).`);
148
+ console.log('If there is quota left, the house holds the tokens and the contract lands in your mailbox.');
149
+ console.log(` read mailbox: npx @nyx5/nyx5 inbox --agent ${o.agent}`);
150
+ console.log(` when done: npx @nyx5/nyx5 libro --agent ${o.agent} --op deliver --args '{"contract":"<id>"}'`);
150
151
  if (o.json) print(enviada);
151
152
  break;
152
153
  }
@@ -159,11 +160,11 @@ try {
159
160
  });
160
161
  if (o.json || !r.mandate) { print(r); break; }
161
162
  const m = r.mandate;
162
- console.log(`Mandato ${m.id} creado.`);
163
- console.log(` ${m.grantee} puede gastar hasta ${m.cap} tokens de la cuenta de ${m.grantor}.`);
164
- if (m.expires) console.log(` Vence: ${m.expires}`);
165
- if (Object.keys(m.scope || {}).length) console.log(` Ámbito: ${JSON.stringify(m.scope)}`);
166
- console.log(` Revocar en cualquier momento: npx @nyx5/nyx5 libro --agent <tu-llave> --op revoke --args '{"mandate":"${m.id}"}'`);
163
+ console.log(`Mandate ${m.id} created.`);
164
+ console.log(` ${m.grantee} may spend up to ${m.cap} tokens from ${m.grantor}'s account.`);
165
+ if (m.expires) console.log(` Expires: ${m.expires}`);
166
+ if (Object.keys(m.scope || {}).length) console.log(` Scope: ${JSON.stringify(m.scope)}`);
167
+ console.log(` Revoke at any time: npx @nyx5/nyx5 libro --agent <your-key> --op revoke --args '{"mandate":"${m.id}"}'`);
167
168
  break;
168
169
  }
169
170
  // ----- Reputación = una consulta al libro (pública) -----
@@ -197,8 +198,8 @@ try {
197
198
  const out = o.out || `./keys/${a.local}.json`;
198
199
  fs.mkdirSync(path.dirname(out), { recursive: true });
199
200
  fs.writeFileSync(out, JSON.stringify({ address: a.address, estafeta: a.estafeta, keys: a.keys }, null, 2), { mode: 0o600 });
200
- console.log(`claves de ${a.address} guardadas en ${out} (guárdalo como una contraseña)`);
201
- console.log(`clave pública de firma: ${a.keys.sig}`);
201
+ console.log(`keys for ${a.address} saved to ${out} (keep it like a password)`);
202
+ console.log(`public signing key: ${a.keys.sig}`);
202
203
  break;
203
204
  }
204
205
  case 'register': {
@@ -231,7 +232,7 @@ try {
231
232
  const base = idx.startsWith('http') ? idx.replace(/\/$/, '') : (await r.domainCard(idx))._estafeta;
232
233
  const params = new URLSearchParams(Object.entries({ q: o.q, capability: o.capability, accepts: o.accepts, house: o.house, limit: o.limit }).filter(([, v]) => v));
233
234
  const d = await (await fetch(`${base}/index/agents?${params}`)).json();
234
- console.log(`${d.total} agente(s) en el índice ${d.index || idx}`);
235
+ console.log(`${d.total} agent(s) in index ${d.index || idx}`);
235
236
  for (const a of d.agents || []) console.log(` ${a.address.padEnd(40)} casa=${a._house || '-'} ${Object.keys(a.capabilities || {}).filter((k) => k !== 'accepts').join(',') || '-'}`);
236
237
  break;
237
238
  }
@@ -251,7 +252,7 @@ try {
251
252
  case 'inbox': {
252
253
  const a = await loadAgent();
253
254
  const msgs = await a.inbox({ limit: Number(o.limit || 50) });
254
- if (!msgs.length) { console.log('buzón vacío'); break; }
255
+ if (!msgs.length) { console.log('mailbox empty'); break; }
255
256
  const abiertos = [];
256
257
  for (const m of msgs) {
257
258
  try { const op = await a.open(m.envelope); const { sender, ...rest } = op; abiertos.push(m.envelope.id); print({ ...rest, received: m.received, relay_verified: m.relay_verified }); }
@@ -293,7 +294,7 @@ try {
293
294
  const out = o.out || `./keys/${sub.local}.json`;
294
295
  fs.mkdirSync(path.dirname(out), { recursive: true });
295
296
  fs.writeFileSync(out, JSON.stringify({ address: sub.address, estafeta: sub.estafeta, keys: sub.keys }, null, 2), { mode: 0o600 });
296
- console.log(`agente delegado ${sub.address} creado; claves en ${out}`); break;
297
+ console.log(`subagent ${sub.address} created; keys in ${out}`); break;
297
298
  }
298
299
  default:
299
300
  console.log(fs.readFileSync(new URL(import.meta.url)).toString().split('\n').slice(1, 33).map((l) => l.replace(/^\/\/ ?/, '')).join('\n'));