Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ managed as a monorepo.

| Plugin | Capabilities | What it does |
| --- | --- | --- |
| [sample](plugins/sample) | varies | Reference sample demonstrating the plugin API (ping, wallet-read, wallet-submit, reserved capabilities). |
| [ens](plugins/ens) | `wallet-read` | Resolve ENS names via the Agent Wallet. |

## Setup
Expand Down
48 changes: 48 additions & 0 deletions plugins/sample/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,48 @@
# sample

Reference sample plugin for the MetaMask Agent Wallet CLI. Demonstrates the plugin API: input schemas, capability declarations, restricted context, and reserved capabilities.

## Commands

| Command | Capability | Notes |
| --- | --- | --- |
| `mm ping [name]` | none | No auth. Input schema + positional args. |
| `mm demo balance` | `wallet-read` | Active address, native balance, tx count via `ctx.publicClient(1)`. |
| `mm demo submit` | `wallet-submit` | Obtains `ctx.walletExecutor`. |
| `mm vault mnemonic` | `mnemonic-read` (reserved) | Declares SRP disclosure; SRP stays host-only. |
| `mm admin config` | `config-write` (reserved) | Declares config-write capability. |
| `mm admin network` | `network-manage` (reserved) | Declares network-manage capability. |

Command paths map to files under `src/commands/` — e.g. `src/commands/demo/balance.ts` → `mm demo balance` / id `demo:balance`.

For the full plugin developer guide, see [plugin-system.md](https://github.com/MetaMask/agentic/blob/main/docs/plugin-system.md) in the agentic repo.

## Install (this plugin only)

One-time CLI configuration. Plugins are beta and off by default:

```bash
mm config set experimentalPlugins true
mm config set experimentalAllowUnverifiedInstalls true # allows local (file:) installs
```

Build and install from this directory:

```bash
yarn install # from the repo root, wires up the workspace
yarn workspace sample run build
mm plugins install "file:$PWD" --accept-permissions # run from plugins/sample
```

Install from the directory, not a packed tarball — the CLI reads `package.json#mm` from the
directory to persist capability approvals for local installs.

Verify and remove:

```bash
mm ping Alice
mm demo balance
mm plugins uninstall sample
```

To build and link every plugin in this repo instead, use `yarn setup` at the repo root.
82 changes: 82 additions & 0 deletions plugins/sample/package.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,82 @@
{
"name": "sample",
"version": "0.1.0",
"description": "Sample MetaMask Agent Wallet (mm) CLI plugin demonstrating the plugin API",
"license": "MIT",
"type": "module",
"keywords": [
"oclif-plugin",
"metamask",
"agent-wallet"
],
"files": [
"dist",
"oclif.manifest.json"
],
"scripts": {
"build": "tsc -p tsconfig.json && oclif manifest",
"prepack": "npm run build",
"type-check": "tsc -p tsconfig.json --noEmit"
},
"oclif": {
"bin": "mm",
"commands": "./dist/commands",
"topicSeparator": " "
},
"mm": {
"schemaVersion": 1,
"minCliVersion": "^6.1.0",
"capabilities": [],
"commands": [
{
"id": "ping",
"capabilities": [],
"dataAccess": []
},
{
"id": "demo:balance",
"capabilities": [
"wallet-read"
],
"dataAccess": [
"balances",
"accounts"
]
},
{
"id": "demo:submit",
"capabilities": [
"wallet-submit"
],
"dataAccess": []
},
{
"id": "vault:mnemonic",
"capabilities": [],
"dataAccess": [
"mnemonic"
]
},
{
"id": "admin:config",
"capabilities": [],
"dataAccess": []
},
{
"id": "admin:network",
"capabilities": [
"network-manage"
],
"dataAccess": []
}
]
},
"peerDependencies": {
"@metamask/agent-wallet": "^6"
},
"devDependencies": {
"@metamask/agent-wallet": "portal:../../../agentic-cli/packages/agentic-cli",
"oclif": "^4",
"typescript": "^5"
}
}
12 changes: 12 additions & 0 deletions plugins/sample/src/commands/admin/config.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
import { type CommandIO, PluginCommand } from "@metamask/agent-wallet/plugin";

export default class SampleConfigCommand extends PluginCommand<{ capability: "config-write"; status: "reserved" }> {
static override requiresAuth = false;
static override requiresInit = false;
static override description = "Sample plugin: config-write capability (reserved for future config mutations)";
protected readonly pluginCommandId = "admin:config";

async execute(_io: CommandIO) {
return { capability: "config-write" as const, status: "reserved" as const };
}
}
12 changes: 12 additions & 0 deletions plugins/sample/src/commands/admin/network.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
import { type CommandIO, PluginCommand } from "@metamask/agent-wallet/plugin";

export default class SampleNetworkCommand extends PluginCommand<{ capability: "network-manage"; status: "reserved" }> {
static override requiresAuth = false;
static override requiresInit = false;
static override description = "Sample plugin: network-manage capability (reserved for future network management)";
protected readonly pluginCommandId = "admin:network";

async execute(_io: CommandIO) {
return { capability: "network-manage" as const, status: "reserved" as const };
}
}
23 changes: 23 additions & 0 deletions plugins/sample/src/commands/demo/balance.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
import { type CommandIO, PluginCommand } from "@metamask/agent-wallet/plugin";

export default class SampleBalanceCommand extends PluginCommand<{ address: string; balanceWei: string; txCount: number }> {
static override requiresAuth = true;
static override description = "Sample plugin: show the active address, on-chain balance, and tx count";
protected readonly pluginCommandId = "demo:balance";

async execute(_io: CommandIO) {
const state = this.ctx.walletStateManager.read();
const address = [...state.byokWallets, ...state.remoteWallets][0]?.address ?? "";
if (!address) {
return { address, balanceWei: "0", txCount: 0 };
}

const client = this.ctx.publicClient(1);
const [balanceWei, txCount] = await Promise.all([
client.getBalance({ address: address as `0x${string}` }),
client.getTransactionCount({ address: address as `0x${string}` }),
]);

return { address, balanceWei: balanceWei.toString(), txCount };
}
}
12 changes: 12 additions & 0 deletions plugins/sample/src/commands/demo/submit.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
import { type CommandIO, PluginCommand } from "@metamask/agent-wallet/plugin";

export default class SampleSubmitCommand extends PluginCommand<{ walletSubmit: "granted" }> {
static override requiresAuth = true;
static override description = "Sample plugin: obtain the wallet executor (capability: wallet-submit)";
protected readonly pluginCommandId = "demo:submit";

async execute(io: CommandIO) {
await this.ctx.walletExecutor(io, this.pluginCommandId);
return { walletSubmit: "granted" as const };
}
}
26 changes: 26 additions & 0 deletions plugins/sample/src/commands/ping.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
import { type CommandIO, InputFieldType, type InputSchema, PluginCommand, schemaToArgs, schemaToFlags } from "@metamask/agent-wallet/plugin";

const inputs = {
name: {
type: InputFieldType.Text,
flag: "name",
message: "Name to greet",
required: false,
prompt: false,
index: 0,
},
} satisfies InputSchema;

export default class SamplePingCommand extends PluginCommand<{ message: string }> {
static override requiresAuth = false;
static override requiresInit = false;
static override description = "Sample plugin: greet without auth (demonstrates the input schema)";
static override flags = schemaToFlags(inputs);
static override args = schemaToArgs(inputs);
protected readonly pluginCommandId = "ping";

async execute(io: CommandIO) {
const { name } = await io.resolveInputs(inputs);
return { message: name ? `pong, ${name}` : "pong" };
}
}
12 changes: 12 additions & 0 deletions plugins/sample/src/commands/vault/mnemonic.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
import { type CommandIO, PluginCommand } from "@metamask/agent-wallet/plugin";

export default class SampleMnemonicCommand extends PluginCommand<{ capability: "mnemonic-read"; status: "reserved" }> {
static override requiresAuth = false;
static override requiresInit = false;
static override description = "Sample plugin: mnemonic-read capability (reserved; SRP is host-only)";
protected readonly pluginCommandId = "vault:mnemonic";

async execute(_io: CommandIO) {
return { capability: "mnemonic-read" as const, status: "reserved" as const };
}
}
14 changes: 14 additions & 0 deletions plugins/sample/tsconfig.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
{
"compilerOptions": {
"target": "ES2022",
"module": "ESNext",
"moduleResolution": "Bundler",
"strict": true,
"outDir": "dist",
"rootDir": "src",
"skipLibCheck": true,
"esModuleInterop": true,
"forceConsistentCasingInFileNames": true
},
"include": ["src"]
}
28 changes: 28 additions & 0 deletions yarn.lock
Original file line number Diff line number Diff line change
Expand Up @@ -654,6 +654,22 @@ __metadata:
languageName: node
linkType: soft

"@metamask/agent-wallet@portal:../../../agentic-cli/packages/agentic-cli::locator=sample%40workspace%3Aplugins%2Fsample":
version: 0.0.0-use.local
resolution: "@metamask/agent-wallet@portal:../../../agentic-cli/packages/agentic-cli::locator=sample%40workspace%3Aplugins%2Fsample"
dependencies:
"@oclif/core": "npm:^4.11.4"
"@oclif/plugin-help": "npm:^6.2.55"
"@oclif/plugin-plugins": "npm:^5.4.37"
"@oclif/plugin-warn-if-update-available": "npm:^3.1.65"
"@toruslabs/base-controllers": "npm:9.12.0"
qrcode-terminal: "npm:^0.12.0"
semver: "npm:^7.7.2"
bin:
mm: dist/index.js
languageName: node
linkType: soft

"@noble/ciphers@npm:1.3.0, @noble/ciphers@npm:^1.3.0":
version: 1.3.0
resolution: "@noble/ciphers@npm:1.3.0"
Expand Down Expand Up @@ -3822,6 +3838,18 @@ __metadata:
languageName: node
linkType: hard

"sample@workspace:plugins/sample":
version: 0.0.0-use.local
resolution: "sample@workspace:plugins/sample"
dependencies:
"@metamask/agent-wallet": "portal:../../../agentic-cli/packages/agentic-cli"
oclif: "npm:^4"
typescript: "npm:^5"
peerDependencies:
"@metamask/agent-wallet": ^6
languageName: unknown
linkType: soft

"semver@npm:^7.1.1, semver@npm:^7.3.5, semver@npm:^7.3.7, semver@npm:^7.5.3, semver@npm:^7.7.2, semver@npm:^7.8.1, semver@npm:^7.8.5":
version: 7.8.5
resolution: "semver@npm:7.8.5"
Expand Down
Loading