@agenticmail/cli 0.6.0 → 0.7.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 +46 -0
  2. package/dist/cli.js +178 -46
  3. package/package.json +1 -1
package/README.md CHANGED
@@ -94,6 +94,7 @@ All commands are available via `agenticmail <command>` or `npx @agenticmail/cli@
94
94
 
95
95
  | Command | Description |
96
96
  |---------|-------------|
97
+ | `agenticmail bootstrap` | ✨ **One-shot, zero-question install.** Designed to be runnable by an AI agent (Claude Code itself) on a user's behalf — no prompts, no decisions, no human in the loop. Provisions Stalwart, generates keys, starts the API as a launchd service, wires Claude Code in, starts the dispatcher daemon. External email relay and SMS are SKIPPED (run `agenticmail setup` interactively later to add them). See [Autonomous install](#autonomous-install) below. |
97
98
  | `agenticmail openclaw` | **Set up AgenticMail for OpenClaw.** Starts infrastructure, creates an agent, configures the plugin, enables agent auto-spawn via hooks, and restarts the OpenClaw gateway. |
98
99
  | `agenticmail claudecode` | **Set up AgenticMail for Claude Code.** ✨ NEW — wires AgenticMail into Claude Code so every agent (Fola, John, …) becomes a callable subagent via the `Agent` tool, AND wakes automatically on incoming mail or tasks. No separate Anthropic key needed — workers ride on your existing Claude OAuth. See the [Claude Code Integration](#claude-code-integration) section below. |
99
100
 
@@ -353,6 +354,51 @@ The `call_agent` tool intelligently spawns sub-agents with:
353
354
 
354
355
  ---
355
356
 
357
+ ## Autonomous install
358
+
359
+ > ✨ **New in 0.7** — `agenticmail bootstrap` lets an AI agent (e.g. Claude Code itself) install AgenticMail from scratch on a user's behalf, with **zero human-in-the-loop prompts**. Designed for the workflow: "User says to Claude Code: install AgenticMail. Claude Code does it. Done."
360
+
361
+ ```bash
362
+ npm install -g @agenticmail/cli
363
+ agenticmail bootstrap
364
+ ```
365
+
366
+ That's the whole flow. The pipeline:
367
+
368
+ 1. `agenticmail setup --yes` — auto-installs Colima/Docker via brew or apt, starts Stalwart, generates a master key, creates a default agent. **Skips email relay and SMS setup** (those need user-owned credentials and aren't required for local multi-agent coordination).
369
+ 2. `agenticmail service install` — registers the launchd plist (or equivalent) so the API auto-starts on boot, and starts it now.
370
+ 3. Waits up to 60 s for the API to answer `/health`.
371
+ 4. `agenticmail claudecode` — provisions the Claude Code bridge agent, writes `~/.claude.json` + `~/.claude/agents/agenticmail-*.md`, starts the dispatcher daemon under PM2.
372
+
373
+ After it finishes, you restart Claude Code and you've got 62 `mcp__agenticmail__*` tools plus one Claude Code subagent per AgenticMail agent.
374
+
375
+ ### What it does NOT set up
376
+
377
+ - **External email relay.** No outbound mail to the public internet. Agents email each other on `@localhost` through Stalwart, which is what the Claude Code integration needs. Run `agenticmail setup` interactively later to add a Gmail relay or a custom domain.
378
+ - **SMS / phone numbers.** Same reason — requires Google Voice credentials.
379
+
380
+ ### Prerequisites bootstrap CAN'T install for you
381
+
382
+ - **Node.js 20+** — needed to run `agenticmail` in the first place. If you're reading this from `npm install`, you already have it.
383
+ - **`brew` (macOS) or `apt` (Linux)** — needed to install Colima/Docker. Most dev machines have one or the other.
384
+ - That's it. No Docker Desktop GUI gates — bootstrap uses Colima on macOS.
385
+
386
+ ### Real example — what to tell Claude Code
387
+
388
+ ```
389
+ User: "Install AgenticMail on this machine and wire it into Claude Code."
390
+ Claude Code: [runs Bash]
391
+ npm install -g @agenticmail/cli@latest pm2
392
+ agenticmail bootstrap
393
+ [~2 minutes later]
394
+ Claude Code: "Done. Restart me and you'll have AgenticMail's full toolbelt
395
+ plus every agent as a callable subagent."
396
+ ```
397
+
398
+ Zero questions, zero clicks, zero decisions for the user.
399
+
400
+ ---
401
+
356
402
  ## Claude Code Integration
357
403
 
358
404
  > ✨ **New in 0.6** — `@agenticmail/claudecode` brings the full AgenticMail multi-agent platform inside [Claude Code](https://claude.com/claude-code). Every AgenticMail agent becomes a callable Claude Code subagent, and agents auto-wake on incoming mail or tasks. **No separate Anthropic API key required — workers reuse your existing Claude OAuth.**
package/dist/cli.js CHANGED
@@ -4547,7 +4547,34 @@ function stopApiServer() {
4547
4547
  return false;
4548
4548
  }
4549
4549
  }
4550
+ var NON_INTERACTIVE = false;
4551
+ function nonInteractiveDefault(value) {
4552
+ return NON_INTERACTIVE ? value : null;
4553
+ }
4550
4554
  async function cmdSetup() {
4555
+ const setupArgs = process.argv.slice(3);
4556
+ if (setupArgs.some((a) => a === "--help" || a === "-h" || a === "help")) {
4557
+ log2("");
4558
+ log2(` ${c2.pinkBg(" \u{1F380} agenticmail setup ")}`);
4559
+ log2("");
4560
+ log2(` ${c2.bold("Usage:")} agenticmail setup [flags]`);
4561
+ log2("");
4562
+ log2(` ${c2.bold("Flags:")}`);
4563
+ log2(` ${c2.green("-y, --yes, --non-interactive")}`);
4564
+ log2(` Skip every prompt and use safe defaults. Provisions Stalwart +`);
4565
+ log2(` master key + a default "secretary" agent; SKIPS external email`);
4566
+ log2(` and SMS setup. Run \`agenticmail setup\` interactively later to`);
4567
+ log2(` add a Gmail relay or your own domain.`);
4568
+ log2(` ${c2.green("-h, --help")}`);
4569
+ log2(` Show this help and exit.`);
4570
+ log2("");
4571
+ return;
4572
+ }
4573
+ if (setupArgs.some((a) => a === "--yes" || a === "-y" || a === "--non-interactive")) {
4574
+ NON_INTERACTIVE = true;
4575
+ log2("");
4576
+ log2(` ${c2.dim("[non-interactive mode \u2014 using safe defaults for every prompt]")}`);
4577
+ }
4551
4578
  log2("");
4552
4579
  log2(` ${c2.bold("\u{1F380} AgenticMail Setup")} `);
4553
4580
  log2("");
@@ -4563,47 +4590,49 @@ async function cmdSetup() {
4563
4590
  log2(` ${c2.dim("4.")} Connect your email`);
4564
4591
  if (hasOpenClaw) log2(` ${c2.dim("5.")} Configure OpenClaw integration`);
4565
4592
  log2("");
4566
- await pick(` ${c2.magenta("Press any key to get started...")} `, [
4567
- "1",
4568
- "2",
4569
- "3",
4570
- "4",
4571
- "5",
4572
- "6",
4573
- "7",
4574
- "8",
4575
- "9",
4576
- "0",
4577
- "a",
4578
- "b",
4579
- "c",
4580
- "d",
4581
- "e",
4582
- "f",
4583
- "g",
4584
- "h",
4585
- "i",
4586
- "j",
4587
- "k",
4588
- "l",
4589
- "m",
4590
- "n",
4591
- "o",
4592
- "p",
4593
- "q",
4594
- "r",
4595
- "s",
4596
- "t",
4597
- "u",
4598
- "v",
4599
- "w",
4600
- "x",
4601
- "y",
4602
- "z",
4603
- " ",
4604
- "\r",
4605
- "\n"
4606
- ]);
4593
+ if (!NON_INTERACTIVE) {
4594
+ await pick(` ${c2.magenta("Press any key to get started...")} `, [
4595
+ "1",
4596
+ "2",
4597
+ "3",
4598
+ "4",
4599
+ "5",
4600
+ "6",
4601
+ "7",
4602
+ "8",
4603
+ "9",
4604
+ "0",
4605
+ "a",
4606
+ "b",
4607
+ "c",
4608
+ "d",
4609
+ "e",
4610
+ "f",
4611
+ "g",
4612
+ "h",
4613
+ "i",
4614
+ "j",
4615
+ "k",
4616
+ "l",
4617
+ "m",
4618
+ "n",
4619
+ "o",
4620
+ "p",
4621
+ "q",
4622
+ "r",
4623
+ "s",
4624
+ "t",
4625
+ "u",
4626
+ "v",
4627
+ "w",
4628
+ "x",
4629
+ "y",
4630
+ "z",
4631
+ " ",
4632
+ "\r",
4633
+ "\n"
4634
+ ]);
4635
+ }
4607
4636
  log2("");
4608
4637
  const setup = new SetupManager();
4609
4638
  log2(` ${c2.bold(`Step 1 of ${totalSteps}`)} ${c2.dim("\u2014")} ${c2.bold("Checking your system")}`);
@@ -4774,7 +4803,7 @@ async function cmdSetup() {
4774
4803
  log2(` ${c2.cyan("2.")} Remove and connect a different email`);
4775
4804
  log2(` ${c2.cyan("3.")} Set up a custom domain instead`);
4776
4805
  log2("");
4777
- const existChoice = await pick(` ${c2.magenta(">")} `, ["1", "2", "3"]);
4806
+ const existChoice = nonInteractiveDefault("1") ?? await pick(` ${c2.magenta(">")} `, ["1", "2", "3"]);
4778
4807
  if (existChoice === "1") {
4779
4808
  choice = "3";
4780
4809
  log2("");
@@ -4798,7 +4827,7 @@ async function cmdSetup() {
4798
4827
  log2(` ${c2.cyan("3.")} Skip for now`);
4799
4828
  log2(` ${c2.dim("You can always set this up later.")}`);
4800
4829
  log2("");
4801
- choice = await pick(` ${c2.magenta(">")} `, ["1", "2", "3"]);
4830
+ choice = nonInteractiveDefault("3") ?? await pick(` ${c2.magenta(">")} `, ["1", "2", "3"]);
4802
4831
  }
4803
4832
  log2("");
4804
4833
  if (choice === "1" || choice === "2") {
@@ -4846,7 +4875,7 @@ async function cmdSetup() {
4846
4875
  log2(` ${c2.dim("Give your AI agent a phone number via Google Voice.")}`);
4847
4876
  log2(` ${c2.dim("This lets agents receive verification codes and send texts.")}`);
4848
4877
  log2("");
4849
- const wantSms = await ask(` ${c2.bold("Set up phone number access?")} ${c2.dim("(y/N)")} `);
4878
+ const wantSms = nonInteractiveDefault("N") ?? await ask(` ${c2.bold("Set up phone number access?")} ${c2.dim("(y/N)")} `);
4850
4879
  if (wantSms.toLowerCase().startsWith("y")) {
4851
4880
  log2("");
4852
4881
  log2(` ${c2.bold("What this does:")}`);
@@ -5591,6 +5620,101 @@ function mergePluginConfig(existing, apiUrl, masterKey, agentApiKey, pluginDir)
5591
5620
  }
5592
5621
  return result;
5593
5622
  }
5623
+ async function cmdBootstrap() {
5624
+ const sub = process.argv.slice(3);
5625
+ if (sub.includes("--help") || sub.includes("-h")) {
5626
+ log2("");
5627
+ log2(` ${c2.pinkBg(" \u{1F380} agenticmail bootstrap ")}`);
5628
+ log2("");
5629
+ log2(` ${c2.bold("Usage:")} agenticmail bootstrap`);
5630
+ log2("");
5631
+ log2(" One-shot, zero-question install. Designed for AI agents (like Claude");
5632
+ log2(" Code) to run on a user's behalf without any prompts.");
5633
+ log2("");
5634
+ log2(" Pipeline:");
5635
+ log2(` ${c2.dim("1.")} agenticmail setup --yes ${c2.dim("(skips email/SMS; local-only)")}`);
5636
+ log2(` ${c2.dim("2.")} agenticmail service install ${c2.dim("(auto-start the API)")}`);
5637
+ log2(` ${c2.dim("3.")} wait for API on http://127.0.0.1:3200/api/agenticmail/health`);
5638
+ log2(` ${c2.dim("4.")} agenticmail claudecode ${c2.dim("(wire Claude Code integration)")}`);
5639
+ log2("");
5640
+ log2(` ${c2.bold("Notes:")}`);
5641
+ log2(" - Docker (or Colima on macOS) will be auto-installed via brew/apt");
5642
+ log2(" if missing. No GUI gates \u2014 uses Colima on macOS, not Docker Desktop.");
5643
+ log2(" - External email relay and SMS setup are SKIPPED. The local");
5644
+ log2(" multi-agent flow works without them. Run `agenticmail setup`");
5645
+ log2(" interactively later if you want outbound mail to the real internet.");
5646
+ log2("");
5647
+ return;
5648
+ }
5649
+ log2("");
5650
+ log2(` ${c2.pinkBg(" \u{1F380} AgenticMail bootstrap \u2014 fully autonomous install ")}`);
5651
+ log2("");
5652
+ log2(` ${c2.dim("No prompts. No human in the loop. Everything is auto-configured.")}`);
5653
+ log2("");
5654
+ log2(` ${c2.bold("Phase 1 of 4")} ${c2.dim("\u2014")} ${c2.bold("Provisioning infrastructure (Stalwart + master key)")}`);
5655
+ log2("");
5656
+ const savedArgv = process.argv.slice();
5657
+ process.argv = [savedArgv[0], savedArgv[1], "setup", "--yes"];
5658
+ try {
5659
+ await cmdSetup();
5660
+ } finally {
5661
+ process.argv = savedArgv;
5662
+ }
5663
+ log2("");
5664
+ log2(` ${c2.bold("Phase 2 of 4")} ${c2.dim("\u2014")} ${c2.bold("Installing the auto-start service")}`);
5665
+ log2("");
5666
+ const savedArgvSvc = process.argv.slice();
5667
+ process.argv = [savedArgvSvc[0], savedArgvSvc[1], "service", "install"];
5668
+ try {
5669
+ await cmdService();
5670
+ } finally {
5671
+ process.argv = savedArgvSvc;
5672
+ }
5673
+ log2("");
5674
+ log2(` ${c2.bold("Phase 3 of 4")} ${c2.dim("\u2014")} ${c2.bold("Waiting for the API to come online")}`);
5675
+ log2("");
5676
+ const apiHealthOk = await waitForApiHealth(6e4);
5677
+ if (!apiHealthOk) {
5678
+ fail2(`API did not respond on http://127.0.0.1:3200/api/agenticmail/health within 60 s`);
5679
+ info2("Check the logs: tail -f ~/.agenticmail/logs/server.log");
5680
+ process.exit(1);
5681
+ }
5682
+ ok2("API server is online and healthy");
5683
+ log2("");
5684
+ log2(` ${c2.bold("Phase 4 of 4")} ${c2.dim("\u2014")} ${c2.bold("Wiring Claude Code integration")}`);
5685
+ log2("");
5686
+ const savedArgvCc = process.argv.slice();
5687
+ process.argv = [savedArgvCc[0], savedArgvCc[1], "claudecode"];
5688
+ try {
5689
+ await cmdClaudeCode();
5690
+ } finally {
5691
+ process.argv = savedArgvCc;
5692
+ }
5693
+ log2("");
5694
+ log2(` ${c2.pinkBg(" \u2705 Bootstrap complete ")}`);
5695
+ log2("");
5696
+ log2(` ${c2.bold("Restart Claude Code")} and you'll have:`);
5697
+ log2(` - 62 ${c2.cyan("mcp__agenticmail__*")} tools in every session`);
5698
+ log2(` - The ${c2.cyan("Agent")} tool surfaces each AgenticMail agent as a subagent`);
5699
+ log2(` - Send mail to ${c2.cyan("<agent>@localhost")} or call_agent \u2192 dispatcher auto-wakes them`);
5700
+ log2("");
5701
+ log2(` ${c2.dim("To add an external email relay later:")} ${c2.green("agenticmail setup")}`);
5702
+ log2("");
5703
+ }
5704
+ async function waitForApiHealth(timeoutMs) {
5705
+ const deadline = Date.now() + timeoutMs;
5706
+ while (Date.now() < deadline) {
5707
+ try {
5708
+ const res = await fetch("http://127.0.0.1:3200/api/agenticmail/health", {
5709
+ signal: AbortSignal.timeout(3e3)
5710
+ });
5711
+ if (res.ok) return true;
5712
+ } catch {
5713
+ }
5714
+ await new Promise((r) => setTimeout(r, 1e3));
5715
+ }
5716
+ return false;
5717
+ }
5594
5718
  async function cmdClaudeCode() {
5595
5719
  const sub = process.argv.slice(3);
5596
5720
  if (sub.includes("--help") || sub.includes("-h") || sub.includes("help")) {
@@ -6021,7 +6145,7 @@ async function cmdOpenClaw() {
6021
6145
  }
6022
6146
  }
6023
6147
  if (!smsAlreadyConfigured) {
6024
- const wantSms = await ask(` ${c2.bold("Set up phone number access?")} ${c2.dim("(y/N)")} `);
6148
+ const wantSms = nonInteractiveDefault("N") ?? await ask(` ${c2.bold("Set up phone number access?")} ${c2.dim("(y/N)")} `);
6025
6149
  if (wantSms.toLowerCase().startsWith("y")) {
6026
6150
  log2("");
6027
6151
  const hasVoice = await ask(` ${c2.bold("Do you already have a Google Voice number?")} ${c2.dim("(y/N)")} `);
@@ -6851,6 +6975,13 @@ switch (command) {
6851
6975
  process.exit(1);
6852
6976
  });
6853
6977
  break;
6978
+ case "bootstrap":
6979
+ case "quickstart":
6980
+ cmdBootstrap().catch((err) => {
6981
+ console.error(err);
6982
+ process.exit(1);
6983
+ });
6984
+ break;
6854
6985
  case "service":
6855
6986
  cmdService().then(() => {
6856
6987
  process.exit(0);
@@ -6888,7 +7019,8 @@ switch (command) {
6888
7019
  log2("");
6889
7020
  log2(" Commands:");
6890
7021
  log2(` ${c2.green("agenticmail")} Get started (setup + start)`);
6891
- log2(` ${c2.green("agenticmail setup")} Re-run the setup wizard`);
7022
+ log2(` ${c2.green("agenticmail bootstrap")} ${c2.dim("Zero-question install \u2014 for AI agents (Claude Code) to run on a user's behalf")}`);
7023
+ log2(` ${c2.green("agenticmail setup")} Re-run the setup wizard ${c2.dim("(use --yes for non-interactive)")}`);
6892
7024
  log2(` ${c2.green("agenticmail start")} Start the server`);
6893
7025
  log2(` ${c2.green("agenticmail stop")} Stop the server`);
6894
7026
  log2(` ${c2.green("agenticmail status")} See what's running`);
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@agenticmail/cli",
3
- "version": "0.6.0",
3
+ "version": "0.7.0",
4
4
  "description": "Email and SMS infrastructure for AI agents — the first platform to give agents real email addresses and phone numbers",
5
5
  "type": "module",
6
6
  "main": "dist/index.js",