@aman_asmuei/aman-agent 0.31.0-next.1 → 0.32.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 CHANGED
@@ -17,13 +17,13 @@
17
17
   
18
18
  <a href="https://github.com/amanasmuei/aman-agent/actions"><img src="https://img.shields.io/github/actions/workflow/status/amanasmuei/aman-agent/ci.yml?style=for-the-badge&logo=github&label=CI" alt="CI status" /></a>
19
19
  &nbsp;
20
- <img src="https://img.shields.io/badge/tests-429_passing-brightgreen?style=for-the-badge&logo=vitest&logoColor=white" alt="429 tests passing" />
20
+ <img src="https://img.shields.io/badge/tests-490_passing-brightgreen?style=for-the-badge&logo=vitest&logoColor=white" alt="490 tests passing" />
21
21
  &nbsp;
22
22
  <a href="LICENSE"><img src="https://img.shields.io/badge/license-MIT-blue?style=for-the-badge" alt="MIT License" /></a>
23
23
  </p>
24
24
 
25
25
  <p align="center">
26
- <img src="https://img.shields.io/badge/node-%E2%89%A520-brightgreen?style=flat-square&logo=node.js&logoColor=white" alt="Node.js 20+" />
26
+ <img src="https://img.shields.io/badge/node-%E2%89%A518-brightgreen?style=flat-square&logo=node.js&logoColor=white" alt="Node.js 18+" />
27
27
  &nbsp;
28
28
  <img src="https://img.shields.io/badge/typescript-strict-3178c6?style=flat-square&logo=typescript&logoColor=white" alt="Strict TypeScript" />
29
29
  &nbsp;
@@ -50,7 +50,7 @@
50
50
 
51
51
  <p align="center">
52
52
  <sub>
53
- <b>Try it in 10 seconds →</b>&nbsp;&nbsp;<code>npx @aman_asmuei/aman-agent</code>
53
+ <b>Install in 10 seconds →</b>&nbsp;&nbsp;<code>curl -fsSL https://raw.githubusercontent.com/amanasmuei/aman-agent/main/install.sh | bash</code>
54
54
  </sub>
55
55
  </p>
56
56
 
@@ -94,40 +94,47 @@
94
94
 
95
95
  ---
96
96
 
97
- ## What's New in v0.30.0
97
+ ## What's New in v0.31.0
98
98
 
99
- > **Agent hardening trust, durability, insight.**<br/>
100
- > The agent now asks before delegating, persists background tasks across crashes, and ships a real analytics dashboard in `/eval report`.
99
+ > **Multi-agent (A2A) via MCP server mode.**<br/>
100
+ > Multiple `aman-agent` instances on the same machine can now discover each other via a local registry and delegate tasks to each other over the MCP protocol. No new wire format, no broker, no new runtime daemon.
101
101
 
102
102
  <table>
103
103
  <tr>
104
104
  <td width="33%" valign="top">
105
105
 
106
- **Delegation confirmation**
106
+ **`aman-agent serve`**
107
107
 
108
- The agent now prompts you before executing `delegate_task` or `team_run`. No more silent autonomous sub-agents you stay in the loop on every hand-off.
108
+ Run any profile as a local MCP server. Registers in `~/.aman-agent/registry.json` (mode `0600`), exposes `agent.info`, `agent.delegate`, and `agent.send` tools over localhost HTTP with bearer auth.
109
109
 
110
110
  </td>
111
111
  <td width="33%" valign="top">
112
112
 
113
- **Persistent background tasks**
113
+ **`/delegate @coder <task>`**
114
114
 
115
- Background task state is written to `~/.aman-agent/bg-tasks.json` on every transition survives crashes, terminal closures, and reboots. Visible in `/eval report`.
115
+ From any other `aman-agent`, delegate to a running serve instance by handle. The `@`-prefix routes through `delegateRemote` which dials via `StreamableHTTPClientTransport` using the bearer from the registry.
116
116
 
117
117
  </td>
118
118
  <td width="33%" valign="top">
119
119
 
120
- **Rich `/eval report`**
120
+ **`/agents list|info|ping`**
121
121
 
122
- Trust score, sentiment trend, energy distribution, burnout risk, frustration correlations, and background-task stats all in one dashboard.
122
+ Discover, inspect, and latency-check every agent currently running on this machine. `/agents list` merges local registry entries with remotes (local wins on name collision).
123
123
 
124
124
  </td>
125
125
  </tr>
126
126
  </table>
127
127
 
128
+ See the [Multi-agent (A2A)](#multi-agent-a2a) section below for the full walkthrough.
129
+
128
130
  <details>
129
131
  <summary><strong>Highlights from earlier releases</strong></summary>
130
132
 
133
+ **v0.30 — Agent hardening**
134
+ - Delegation confirmation prompts (no more silent sub-agents)
135
+ - Persistent background task state surviving crashes
136
+ - Rich `/eval report` with trust, sentiment, energy, burnout risk
137
+
131
138
  **v0.29 — Ecosystem parity**
132
139
  - Auto-relate memories after extraction (knowledge graph edges)
133
140
  - Stale reference cleanup
@@ -243,7 +250,7 @@ flowchart LR
243
250
  | `llm/` | 6 pluggable providers — Anthropic, OpenAI, Ollama, GitHub Copilot, OpenAI-compatible, Claude Code CLI | `src/llm/` |
244
251
  | `mcp/` | MCP v1.27 client with stdio transport and auto-reconnect | `src/mcp/` |
245
252
 
246
- **Stateless by default.** All state lives in `~/.acore`, `~/.arules`, `~/.aflow`, `~/.askill`, `~/.aeval`, and `~/.amem` — portable, inspectable markdown + a local SQLite file. Nothing leaves your machine except what you send to your chosen LLM.
253
+ **Stateless by default.** All state lives in `~/.aman-agent/` identity, rules, workflows, skills, eval, and memory in one portable directory. Nothing leaves your machine except what you send to your chosen LLM.
247
254
 
248
255
  </details>
249
256
 
@@ -251,14 +258,23 @@ flowchart LR
251
258
 
252
259
  ## Quick Start
253
260
 
254
- ### 1. Run
261
+ ### 1. Install
255
262
 
256
263
  ```bash
257
- # Run directly (always latest)
258
- npx @aman_asmuei/aman-agent
264
+ # One-liner install (no Node.js required) — Linux, macOS, Raspberry Pi
265
+ curl -fsSL https://raw.githubusercontent.com/amanasmuei/aman-agent/main/install.sh | bash
259
266
 
260
- # Or install globally
267
+ # Or via npm (if you already have Node.js 18+)
261
268
  npm install -g @aman_asmuei/aman-agent
269
+
270
+ # Or via Docker
271
+ docker run -it -e ANTHROPIC_API_KEY=sk-... ghcr.io/amanasmuei/aman-agent
272
+ ```
273
+
274
+ ### 2. Run
275
+
276
+ ```bash
277
+ aman-agent
262
278
  ```
263
279
 
264
280
  **Zero config if you already have an API key in your environment:**
package/dist/delegate.js CHANGED
@@ -9,22 +9,22 @@ var __export = (target, all) => {
9
9
  };
10
10
 
11
11
  // src/logger.ts
12
- import fs3 from "fs";
13
- import path3 from "path";
12
+ import fs4 from "fs";
13
+ import path4 from "path";
14
14
  import os3 from "os";
15
15
  function ensureDir() {
16
- if (!fs3.existsSync(LOG_DIR)) {
17
- fs3.mkdirSync(LOG_DIR, { recursive: true });
16
+ if (!fs4.existsSync(LOG_DIR)) {
17
+ fs4.mkdirSync(LOG_DIR, { recursive: true });
18
18
  }
19
19
  }
20
20
  function maybeRotate() {
21
21
  try {
22
- if (!fs3.existsSync(LOG_PATH)) return;
23
- const stat = fs3.statSync(LOG_PATH);
22
+ if (!fs4.existsSync(LOG_PATH)) return;
23
+ const stat = fs4.statSync(LOG_PATH);
24
24
  if (stat.size >= MAX_LOG_SIZE) {
25
25
  const backupPath = LOG_PATH + ".1";
26
- if (fs3.existsSync(backupPath)) fs3.unlinkSync(backupPath);
27
- fs3.renameSync(LOG_PATH, backupPath);
26
+ if (fs4.existsSync(backupPath)) fs4.unlinkSync(backupPath);
27
+ fs4.renameSync(LOG_PATH, backupPath);
28
28
  }
29
29
  } catch {
30
30
  }
@@ -42,7 +42,7 @@ function write(level, module, message, data) {
42
42
  if (data !== void 0) {
43
43
  entry.data = data instanceof Error ? data.message : String(data);
44
44
  }
45
- fs3.appendFileSync(LOG_PATH, JSON.stringify(entry) + "\n");
45
+ fs4.appendFileSync(LOG_PATH, JSON.stringify(entry) + "\n");
46
46
  } catch {
47
47
  }
48
48
  }
@@ -50,8 +50,8 @@ var LOG_DIR, LOG_PATH, MAX_LOG_SIZE, log;
50
50
  var init_logger = __esm({
51
51
  "src/logger.ts"() {
52
52
  "use strict";
53
- LOG_DIR = path3.join(os3.homedir(), ".aman-agent");
54
- LOG_PATH = path3.join(LOG_DIR, "debug.log");
53
+ LOG_DIR = path4.join(os3.homedir(), ".aman-agent");
54
+ LOG_PATH = path4.join(LOG_DIR, "debug.log");
55
55
  MAX_LOG_SIZE = 1048576;
56
56
  log = {
57
57
  debug: (module, message, data) => write("debug", module, message, data),
@@ -62,21 +62,21 @@ var init_logger = __esm({
62
62
  });
63
63
 
64
64
  // src/server/registry.ts
65
- import fs10 from "fs/promises";
66
- import path10 from "path";
65
+ import fs11 from "fs/promises";
66
+ import path11 from "path";
67
67
  import os9 from "os";
68
68
  function amanAgentHome() {
69
- return process.env.AMAN_AGENT_HOME || path10.join(os9.homedir(), ".aman-agent");
69
+ return process.env.AMAN_AGENT_HOME || path11.join(os9.homedir(), ".aman-agent");
70
70
  }
71
71
  function registryPath() {
72
- return path10.join(amanAgentHome(), "registry.json");
72
+ return path11.join(amanAgentHome(), "registry.json");
73
73
  }
74
74
  async function ensureHome() {
75
- await fs10.mkdir(amanAgentHome(), { recursive: true });
75
+ await fs11.mkdir(amanAgentHome(), { recursive: true });
76
76
  }
77
77
  async function readRaw() {
78
78
  try {
79
- const buf = await fs10.readFile(registryPath(), "utf-8");
79
+ const buf = await fs11.readFile(registryPath(), "utf-8");
80
80
  const parsed = JSON.parse(buf);
81
81
  return Array.isArray(parsed) ? parsed : [];
82
82
  } catch (err) {
@@ -90,10 +90,10 @@ async function readRaw() {
90
90
  async function writeAtomic(entries) {
91
91
  await ensureHome();
92
92
  const tmp = registryPath() + ".tmp";
93
- await fs10.writeFile(tmp, JSON.stringify(entries, null, 2), { mode: 384 });
94
- await fs10.rename(tmp, registryPath());
93
+ await fs11.writeFile(tmp, JSON.stringify(entries, null, 2), { mode: 384 });
94
+ await fs11.rename(tmp, registryPath());
95
95
  try {
96
- await fs10.chmod(registryPath(), 384);
96
+ await fs11.chmod(registryPath(), 384);
97
97
  } catch {
98
98
  }
99
99
  }
@@ -264,8 +264,8 @@ var init_delegate_remote = __esm({
264
264
  import pc2 from "picocolors";
265
265
 
266
266
  // src/prompt.ts
267
- import fs2 from "fs";
268
- import path2 from "path";
267
+ import fs3 from "fs";
268
+ import path3 from "path";
269
269
  import os2 from "os";
270
270
 
271
271
  // src/token-budget.ts
@@ -322,14 +322,26 @@ function buildBudgetedPrompt(components, maxTokens = 8e3) {
322
322
  }
323
323
 
324
324
  // src/user-identity.ts
325
+ import fs2 from "fs";
326
+ import path2 from "path";
327
+
328
+ // src/config.ts
325
329
  import fs from "fs";
326
330
  import path from "path";
327
331
  import os from "os";
328
- var USER_FILE = path.join(os.homedir(), ".acore", "user.md");
332
+ function homeDir() {
333
+ return process.env.AMAN_HOME || process.env.AMAN_AGENT_HOME || path.join(os.homedir(), ".aman-agent");
334
+ }
335
+ function identityDir() {
336
+ return path.join(homeDir(), "identity");
337
+ }
338
+
339
+ // src/user-identity.ts
340
+ var USER_FILE = path2.join(identityDir(), "user.md");
329
341
  function loadUserIdentity() {
330
- if (!fs.existsSync(USER_FILE)) return null;
342
+ if (!fs2.existsSync(USER_FILE)) return null;
331
343
  try {
332
- const content = fs.readFileSync(USER_FILE, "utf-8");
344
+ const content = fs2.readFileSync(USER_FILE, "utf-8");
333
345
  const get = (key) => {
334
346
  const match = content.match(new RegExp(`^- ${key}:\\s*(.+)$`, "m"));
335
347
  return match?.[1]?.trim() ?? "";
@@ -419,19 +431,19 @@ var ECOSYSTEM_FILES = [
419
431
  ];
420
432
  function resolveLayerPath(entry, home, profile) {
421
433
  if (profile && entry.profileOverridable) {
422
- const profilePath = path2.join(home, ".acore", "profiles", profile, entry.file);
423
- if (fs2.existsSync(profilePath)) return profilePath;
434
+ const profilePath = path3.join(home, ".acore", "profiles", profile, entry.file);
435
+ if (fs3.existsSync(profilePath)) return profilePath;
424
436
  if (entry.name === "guardrails") {
425
- const altPath = path2.join(home, ".acore", "profiles", profile, "rules.md");
426
- if (fs2.existsSync(altPath)) return altPath;
437
+ const altPath = path3.join(home, ".acore", "profiles", profile, "rules.md");
438
+ if (fs3.existsSync(altPath)) return altPath;
427
439
  }
428
440
  if (entry.name === "skills") {
429
- const altPath = path2.join(home, ".acore", "profiles", profile, "skills.md");
430
- if (fs2.existsSync(altPath)) return altPath;
441
+ const altPath = path3.join(home, ".acore", "profiles", profile, "skills.md");
442
+ if (fs3.existsSync(altPath)) return altPath;
431
443
  }
432
444
  }
433
- const globalPath = path2.join(home, entry.dir, entry.file);
434
- if (fs2.existsSync(globalPath)) return globalPath;
445
+ const globalPath = path3.join(home, entry.dir, entry.file);
446
+ if (fs3.existsSync(globalPath)) return globalPath;
435
447
  return null;
436
448
  }
437
449
  function assembleSystemPrompt(maxTokens, profile) {
@@ -440,7 +452,7 @@ function assembleSystemPrompt(maxTokens, profile) {
440
452
  for (const entry of ECOSYSTEM_FILES) {
441
453
  const filePath = resolveLayerPath(entry, home, profile);
442
454
  if (filePath) {
443
- const content = fs2.readFileSync(filePath, "utf-8").trim();
455
+ const content = fs3.readFileSync(filePath, "utf-8").trim();
444
456
  components.push({
445
457
  name: entry.name,
446
458
  content,
@@ -448,9 +460,9 @@ function assembleSystemPrompt(maxTokens, profile) {
448
460
  });
449
461
  }
450
462
  }
451
- const contextPath = path2.join(process.cwd(), ".acore", "context.md");
452
- if (fs2.existsSync(contextPath)) {
453
- const content = fs2.readFileSync(contextPath, "utf-8").trim();
463
+ const contextPath = path3.join(process.cwd(), ".acore", "context.md");
464
+ if (fs3.existsSync(contextPath)) {
465
+ const content = fs3.readFileSync(contextPath, "utf-8").trim();
454
466
  components.push({
455
467
  name: "context",
456
468
  content,
@@ -502,8 +514,8 @@ init_logger();
502
514
  init_logger();
503
515
  import pc from "picocolors";
504
516
  import * as p from "@clack/prompts";
505
- import fs9 from "fs";
506
- import path9 from "path";
517
+ import fs10 from "fs";
518
+ import path10 from "path";
507
519
  import os8 from "os";
508
520
 
509
521
  // src/personality.ts
@@ -534,9 +546,9 @@ import {
534
546
  importFromTeam,
535
547
  syncToCopilot
536
548
  } from "@aman_asmuei/amem-core";
537
- import path4 from "path";
549
+ import path5 from "path";
538
550
  import os4 from "os";
539
- import fs4 from "fs";
551
+ import fs5 from "fs";
540
552
  var db = null;
541
553
  var currentProject = "global";
542
554
  function getDb() {
@@ -557,13 +569,13 @@ async function memoryRecall(query, opts) {
557
569
  }
558
570
 
559
571
  // src/postmortem.ts
560
- import fs6 from "fs/promises";
561
- import path6 from "path";
572
+ import fs7 from "fs/promises";
573
+ import path7 from "path";
562
574
  import os6 from "os";
563
575
 
564
576
  // src/observation.ts
565
- import fs5 from "fs/promises";
566
- import path5 from "path";
577
+ import fs6 from "fs/promises";
578
+ import path6 from "path";
567
579
  import os5 from "os";
568
580
 
569
581
  // src/postmortem.ts
@@ -571,12 +583,12 @@ init_logger();
571
583
 
572
584
  // src/crystallization.ts
573
585
  init_logger();
574
- import fs7 from "fs/promises";
575
- import path7 from "path";
576
-
577
- // src/user-model.ts
578
586
  import fs8 from "fs/promises";
579
587
  import path8 from "path";
588
+
589
+ // src/user-model.ts
590
+ import fs9 from "fs/promises";
591
+ import path9 from "path";
580
592
  import os7 from "os";
581
593
 
582
594
  // src/hooks.ts