@enshell/cli 0.1.0-beta.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/LICENSE +21 -0
- package/README.md +73 -0
- package/dist/commands/approve.d.ts +2 -0
- package/dist/commands/approve.js +26 -0
- package/dist/commands/approve.js.map +1 -0
- package/dist/commands/connect.d.ts +2 -0
- package/dist/commands/connect.js +20 -0
- package/dist/commands/connect.js.map +1 -0
- package/dist/commands/deactivate.d.ts +2 -0
- package/dist/commands/deactivate.js +26 -0
- package/dist/commands/deactivate.js.map +1 -0
- package/dist/commands/disconnect.d.ts +2 -0
- package/dist/commands/disconnect.js +19 -0
- package/dist/commands/disconnect.js.map +1 -0
- package/dist/commands/inspect.d.ts +2 -0
- package/dist/commands/inspect.js +32 -0
- package/dist/commands/inspect.js.map +1 -0
- package/dist/commands/list.d.ts +2 -0
- package/dist/commands/list.js +32 -0
- package/dist/commands/list.js.map +1 -0
- package/dist/commands/protect.d.ts +2 -0
- package/dist/commands/protect.js +54 -0
- package/dist/commands/protect.js.map +1 -0
- package/dist/commands/reactivate.d.ts +2 -0
- package/dist/commands/reactivate.js +26 -0
- package/dist/commands/reactivate.js.map +1 -0
- package/dist/commands/register.d.ts +2 -0
- package/dist/commands/register.js +33 -0
- package/dist/commands/register.js.map +1 -0
- package/dist/commands/reject.d.ts +2 -0
- package/dist/commands/reject.js +26 -0
- package/dist/commands/reject.js.map +1 -0
- package/dist/commands/submit.d.ts +2 -0
- package/dist/commands/submit.js +32 -0
- package/dist/commands/submit.js.map +1 -0
- package/dist/config.d.ts +10 -0
- package/dist/config.js +30 -0
- package/dist/config.js.map +1 -0
- package/dist/index.d.ts +2 -0
- package/dist/index.js +39 -0
- package/dist/index.js.map +1 -0
- package/dist/wallets/env.d.ts +7 -0
- package/dist/wallets/env.js +17 -0
- package/dist/wallets/env.js.map +1 -0
- package/dist/wallets/index.d.ts +10 -0
- package/dist/wallets/index.js +22 -0
- package/dist/wallets/index.js.map +1 -0
- package/dist/wallets/storage.d.ts +19 -0
- package/dist/wallets/storage.js +62 -0
- package/dist/wallets/storage.js.map +1 -0
- package/dist/wallets/walletconnect.d.ts +17 -0
- package/dist/wallets/walletconnect.js +94 -0
- package/dist/wallets/walletconnect.js.map +1 -0
- package/package.json +38 -0
package/LICENSE
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2026 ENShell
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
SOFTWARE.
|
package/README.md
ADDED
|
@@ -0,0 +1,73 @@
|
|
|
1
|
+
# ENShell CLI
|
|
2
|
+
|
|
3
|
+
[](https://codecov.io/gh/0xenshell/cli)
|
|
4
|
+
|
|
5
|
+
Command-line interface for **ENShell**, an on-chain firewall for AI agents. Register agents, submit actions through the firewall, approve or reject queued actions, and manage agent lifecycle. Built with Commander.js and the [@enshell/sdk](https://www.npmjs.com/package/@enshell/sdk).
|
|
6
|
+
|
|
7
|
+
## Setup
|
|
8
|
+
|
|
9
|
+
```bash
|
|
10
|
+
npm install
|
|
11
|
+
cp .env.example .env
|
|
12
|
+
# Edit .env with your RPC URL, private key, and contract address
|
|
13
|
+
```
|
|
14
|
+
|
|
15
|
+
## Configuration
|
|
16
|
+
|
|
17
|
+
The CLI reads from environment variables (via `.env`):
|
|
18
|
+
|
|
19
|
+
| Variable | Description |
|
|
20
|
+
|---|---|
|
|
21
|
+
| `ENSHELL_RPC_URL` | Ethereum RPC endpoint |
|
|
22
|
+
| `ENSHELL_PRIVATE_KEY` | Wallet private key (owner of the firewall contract) |
|
|
23
|
+
| `ENSHELL_CONTRACT_ADDRESS` | Deployed AgentFirewall contract address |
|
|
24
|
+
|
|
25
|
+
## Build
|
|
26
|
+
|
|
27
|
+
```bash
|
|
28
|
+
npm run build
|
|
29
|
+
```
|
|
30
|
+
|
|
31
|
+
## Test
|
|
32
|
+
|
|
33
|
+
```bash
|
|
34
|
+
npm test
|
|
35
|
+
```
|
|
36
|
+
|
|
37
|
+
## Commands
|
|
38
|
+
|
|
39
|
+
### Agent Management
|
|
40
|
+
|
|
41
|
+
```bash
|
|
42
|
+
# Register a new agent (ENS subdomain trader.enshell.eth is computed automatically)
|
|
43
|
+
enshell register --id trader --agent-wallet 0x... --spend-limit 0.1 --targets 0x... 0x...
|
|
44
|
+
|
|
45
|
+
# List all registered agents
|
|
46
|
+
enshell list
|
|
47
|
+
|
|
48
|
+
# Inspect an agent
|
|
49
|
+
enshell inspect --id trader
|
|
50
|
+
|
|
51
|
+
# Deactivate (freeze) an agent
|
|
52
|
+
enshell deactivate --id trader
|
|
53
|
+
|
|
54
|
+
# Reactivate a frozen agent
|
|
55
|
+
enshell reactivate --id trader
|
|
56
|
+
```
|
|
57
|
+
|
|
58
|
+
### Action Firewall
|
|
59
|
+
|
|
60
|
+
```bash
|
|
61
|
+
# Submit an action through the firewall
|
|
62
|
+
enshell submit --id trader --target 0x... --value 0.05 --instruction "Send 0.05 ETH to treasury"
|
|
63
|
+
|
|
64
|
+
# Approve a queued action (Ledger approval)
|
|
65
|
+
enshell approve --action-id 0
|
|
66
|
+
|
|
67
|
+
# Reject a queued action
|
|
68
|
+
enshell reject --action-id 0
|
|
69
|
+
```
|
|
70
|
+
|
|
71
|
+
## License
|
|
72
|
+
|
|
73
|
+
MIT
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
import { Command } from "commander";
|
|
2
|
+
import chalk from "chalk";
|
|
3
|
+
import ora from "ora";
|
|
4
|
+
import { ENShell, Network } from "@enshell/sdk";
|
|
5
|
+
import { getSigner } from "../config.js";
|
|
6
|
+
export const approveCommand = new Command("approve")
|
|
7
|
+
.description("Approve a queued action")
|
|
8
|
+
.requiredOption("--action-id <id>", "Queued action ID")
|
|
9
|
+
.action(async (opts) => {
|
|
10
|
+
const spinner = ora("Approving action...").start();
|
|
11
|
+
try {
|
|
12
|
+
const signer = await getSigner();
|
|
13
|
+
const client = new ENShell({
|
|
14
|
+
network: Network.SEPOLIA,
|
|
15
|
+
signer,
|
|
16
|
+
});
|
|
17
|
+
const { txHash } = await client.approveAction(BigInt(opts.actionId));
|
|
18
|
+
spinner.succeed(chalk.green(`Action #${opts.actionId} approved`));
|
|
19
|
+
console.log(chalk.gray(` tx: https://sepolia.etherscan.io/tx/${txHash}`));
|
|
20
|
+
}
|
|
21
|
+
catch (err) {
|
|
22
|
+
spinner.fail(chalk.red(`Approval failed: ${err.message}`));
|
|
23
|
+
process.exit(1);
|
|
24
|
+
}
|
|
25
|
+
});
|
|
26
|
+
//# sourceMappingURL=approve.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"approve.js","sourceRoot":"","sources":["../../src/commands/approve.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,OAAO,EAAE,MAAM,WAAW,CAAC;AACpC,OAAO,KAAK,MAAM,OAAO,CAAC;AAC1B,OAAO,GAAG,MAAM,KAAK,CAAC;AACtB,OAAO,EAAE,OAAO,EAAE,OAAO,EAAE,MAAM,cAAc,CAAC;AAChD,OAAO,EAAE,SAAS,EAAE,MAAM,cAAc,CAAC;AAEzC,MAAM,CAAC,MAAM,cAAc,GAAG,IAAI,OAAO,CAAC,SAAS,CAAC;KACjD,WAAW,CAAC,yBAAyB,CAAC;KACtC,cAAc,CAAC,kBAAkB,EAAE,kBAAkB,CAAC;KACtD,MAAM,CAAC,KAAK,EAAE,IAAI,EAAE,EAAE;IACrB,MAAM,OAAO,GAAG,GAAG,CAAC,qBAAqB,CAAC,CAAC,KAAK,EAAE,CAAC;IAEnD,IAAI,CAAC;QACH,MAAM,MAAM,GAAG,MAAM,SAAS,EAAE,CAAC;QACjC,MAAM,MAAM,GAAG,IAAI,OAAO,CAAC;YACzB,OAAO,EAAE,OAAO,CAAC,OAAO;YACxB,MAAM;SACP,CAAC,CAAC;QAEH,MAAM,EAAE,MAAM,EAAE,GAAG,MAAM,MAAM,CAAC,aAAa,CAAC,MAAM,CAAC,IAAI,CAAC,QAAQ,CAAC,CAAC,CAAC;QAErE,OAAO,CAAC,OAAO,CAAC,KAAK,CAAC,KAAK,CAAC,WAAW,IAAI,CAAC,QAAQ,WAAW,CAAC,CAAC,CAAC;QAClE,OAAO,CAAC,GAAG,CAAC,KAAK,CAAC,IAAI,CAAC,yCAAyC,MAAM,EAAE,CAAC,CAAC,CAAC;IAC7E,CAAC;IAAC,OAAO,GAAQ,EAAE,CAAC;QAClB,OAAO,CAAC,IAAI,CAAC,KAAK,CAAC,GAAG,CAAC,oBAAoB,GAAG,CAAC,OAAO,EAAE,CAAC,CAAC,CAAC;QAC3D,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;IAClB,CAAC;AACH,CAAC,CAAC,CAAC"}
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
import { Command } from "commander";
|
|
2
|
+
import chalk from "chalk";
|
|
3
|
+
import ora from "ora";
|
|
4
|
+
import { wcConnect } from "../wallets/walletconnect.js";
|
|
5
|
+
export const connectCommand = new Command("connect")
|
|
6
|
+
.description("Connect your wallet via WalletConnect")
|
|
7
|
+
.action(async () => {
|
|
8
|
+
const spinner = ora("Initializing WalletConnect...").start();
|
|
9
|
+
try {
|
|
10
|
+
spinner.stop();
|
|
11
|
+
const address = await wcConnect();
|
|
12
|
+
console.log(chalk.green(`\n Connected: ${address}`));
|
|
13
|
+
console.log(chalk.gray(" Session saved. You can now run any enshell command.\n"));
|
|
14
|
+
}
|
|
15
|
+
catch (err) {
|
|
16
|
+
spinner.fail(chalk.red(`Connection failed: ${err.message}`));
|
|
17
|
+
process.exit(1);
|
|
18
|
+
}
|
|
19
|
+
});
|
|
20
|
+
//# sourceMappingURL=connect.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"connect.js","sourceRoot":"","sources":["../../src/commands/connect.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,OAAO,EAAE,MAAM,WAAW,CAAC;AACpC,OAAO,KAAK,MAAM,OAAO,CAAC;AAC1B,OAAO,GAAG,MAAM,KAAK,CAAC;AACtB,OAAO,EAAE,SAAS,EAAE,MAAM,6BAA6B,CAAC;AAExD,MAAM,CAAC,MAAM,cAAc,GAAG,IAAI,OAAO,CAAC,SAAS,CAAC;KACjD,WAAW,CAAC,uCAAuC,CAAC;KACpD,MAAM,CAAC,KAAK,IAAI,EAAE;IACjB,MAAM,OAAO,GAAG,GAAG,CAAC,+BAA+B,CAAC,CAAC,KAAK,EAAE,CAAC;IAE7D,IAAI,CAAC;QACH,OAAO,CAAC,IAAI,EAAE,CAAC;QACf,MAAM,OAAO,GAAG,MAAM,SAAS,EAAE,CAAC;QAClC,OAAO,CAAC,GAAG,CAAC,KAAK,CAAC,KAAK,CAAC,kBAAkB,OAAO,EAAE,CAAC,CAAC,CAAC;QACtD,OAAO,CAAC,GAAG,CACT,KAAK,CAAC,IAAI,CAAC,yDAAyD,CAAC,CACtE,CAAC;IACJ,CAAC;IAAC,OAAO,GAAQ,EAAE,CAAC;QAClB,OAAO,CAAC,IAAI,CAAC,KAAK,CAAC,GAAG,CAAC,sBAAsB,GAAG,CAAC,OAAO,EAAE,CAAC,CAAC,CAAC;QAC7D,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;IAClB,CAAC;AACH,CAAC,CAAC,CAAC"}
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
import { Command } from "commander";
|
|
2
|
+
import chalk from "chalk";
|
|
3
|
+
import ora from "ora";
|
|
4
|
+
import { ENShell, Network } from "@enshell/sdk";
|
|
5
|
+
import { getSigner } from "../config.js";
|
|
6
|
+
export const deactivateCommand = new Command("deactivate")
|
|
7
|
+
.description("Deactivate (freeze) an agent")
|
|
8
|
+
.requiredOption("--id <agentId>", "Agent identifier")
|
|
9
|
+
.action(async (opts) => {
|
|
10
|
+
const spinner = ora("Deactivating agent...").start();
|
|
11
|
+
try {
|
|
12
|
+
const signer = await getSigner();
|
|
13
|
+
const client = new ENShell({
|
|
14
|
+
network: Network.SEPOLIA,
|
|
15
|
+
signer,
|
|
16
|
+
});
|
|
17
|
+
const { txHash } = await client.deactivateAgent(opts.id);
|
|
18
|
+
spinner.succeed(chalk.green(`Agent "${opts.id}" deactivated`));
|
|
19
|
+
console.log(chalk.gray(` tx: https://sepolia.etherscan.io/tx/${txHash}`));
|
|
20
|
+
}
|
|
21
|
+
catch (err) {
|
|
22
|
+
spinner.fail(chalk.red(`Deactivation failed: ${err.message}`));
|
|
23
|
+
process.exit(1);
|
|
24
|
+
}
|
|
25
|
+
});
|
|
26
|
+
//# sourceMappingURL=deactivate.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"deactivate.js","sourceRoot":"","sources":["../../src/commands/deactivate.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,OAAO,EAAE,MAAM,WAAW,CAAC;AACpC,OAAO,KAAK,MAAM,OAAO,CAAC;AAC1B,OAAO,GAAG,MAAM,KAAK,CAAC;AACtB,OAAO,EAAE,OAAO,EAAE,OAAO,EAAE,MAAM,cAAc,CAAC;AAChD,OAAO,EAAE,SAAS,EAAE,MAAM,cAAc,CAAC;AAEzC,MAAM,CAAC,MAAM,iBAAiB,GAAG,IAAI,OAAO,CAAC,YAAY,CAAC;KACvD,WAAW,CAAC,8BAA8B,CAAC;KAC3C,cAAc,CAAC,gBAAgB,EAAE,kBAAkB,CAAC;KACpD,MAAM,CAAC,KAAK,EAAE,IAAI,EAAE,EAAE;IACrB,MAAM,OAAO,GAAG,GAAG,CAAC,uBAAuB,CAAC,CAAC,KAAK,EAAE,CAAC;IAErD,IAAI,CAAC;QACH,MAAM,MAAM,GAAG,MAAM,SAAS,EAAE,CAAC;QACjC,MAAM,MAAM,GAAG,IAAI,OAAO,CAAC;YACzB,OAAO,EAAE,OAAO,CAAC,OAAO;YACxB,MAAM;SACP,CAAC,CAAC;QAEH,MAAM,EAAE,MAAM,EAAE,GAAG,MAAM,MAAM,CAAC,eAAe,CAAC,IAAI,CAAC,EAAE,CAAC,CAAC;QAEzD,OAAO,CAAC,OAAO,CAAC,KAAK,CAAC,KAAK,CAAC,UAAU,IAAI,CAAC,EAAE,eAAe,CAAC,CAAC,CAAC;QAC/D,OAAO,CAAC,GAAG,CAAC,KAAK,CAAC,IAAI,CAAC,yCAAyC,MAAM,EAAE,CAAC,CAAC,CAAC;IAC7E,CAAC;IAAC,OAAO,GAAQ,EAAE,CAAC;QAClB,OAAO,CAAC,IAAI,CAAC,KAAK,CAAC,GAAG,CAAC,wBAAwB,GAAG,CAAC,OAAO,EAAE,CAAC,CAAC,CAAC;QAC/D,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;IAClB,CAAC;AACH,CAAC,CAAC,CAAC"}
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
import { Command } from "commander";
|
|
2
|
+
import chalk from "chalk";
|
|
3
|
+
import { wcDisconnect } from "../wallets/walletconnect.js";
|
|
4
|
+
export const disconnectCommand = new Command("disconnect")
|
|
5
|
+
.description("Disconnect wallet and clear saved session")
|
|
6
|
+
.action(async () => {
|
|
7
|
+
try {
|
|
8
|
+
await wcDisconnect();
|
|
9
|
+
console.log(chalk.green(" Wallet disconnected. Session cleared."));
|
|
10
|
+
}
|
|
11
|
+
catch (err) {
|
|
12
|
+
console.log(chalk.yellow(` ${err.message}`));
|
|
13
|
+
// Clear session file anyway
|
|
14
|
+
const { FileStorage } = await import("../wallets/storage.js");
|
|
15
|
+
FileStorage.clear();
|
|
16
|
+
console.log(chalk.green(" Session file cleared."));
|
|
17
|
+
}
|
|
18
|
+
});
|
|
19
|
+
//# sourceMappingURL=disconnect.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"disconnect.js","sourceRoot":"","sources":["../../src/commands/disconnect.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,OAAO,EAAE,MAAM,WAAW,CAAC;AACpC,OAAO,KAAK,MAAM,OAAO,CAAC;AAC1B,OAAO,EAAE,YAAY,EAAE,MAAM,6BAA6B,CAAC;AAE3D,MAAM,CAAC,MAAM,iBAAiB,GAAG,IAAI,OAAO,CAAC,YAAY,CAAC;KACvD,WAAW,CAAC,2CAA2C,CAAC;KACxD,MAAM,CAAC,KAAK,IAAI,EAAE;IACjB,IAAI,CAAC;QACH,MAAM,YAAY,EAAE,CAAC;QACrB,OAAO,CAAC,GAAG,CAAC,KAAK,CAAC,KAAK,CAAC,yCAAyC,CAAC,CAAC,CAAC;IACtE,CAAC;IAAC,OAAO,GAAQ,EAAE,CAAC;QAClB,OAAO,CAAC,GAAG,CAAC,KAAK,CAAC,MAAM,CAAC,KAAK,GAAG,CAAC,OAAO,EAAE,CAAC,CAAC,CAAC;QAC9C,4BAA4B;QAC5B,MAAM,EAAE,WAAW,EAAE,GAAG,MAAM,MAAM,CAAC,uBAAuB,CAAC,CAAC;QAC9D,WAAW,CAAC,KAAK,EAAE,CAAC;QACpB,OAAO,CAAC,GAAG,CAAC,KAAK,CAAC,KAAK,CAAC,yBAAyB,CAAC,CAAC,CAAC;IACtD,CAAC;AACH,CAAC,CAAC,CAAC"}
|
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
import { Command } from "commander";
|
|
2
|
+
import chalk from "chalk";
|
|
3
|
+
import ora from "ora";
|
|
4
|
+
import { formatEther } from "ethers";
|
|
5
|
+
import { getContract } from "../config.js";
|
|
6
|
+
export const inspectCommand = new Command("inspect")
|
|
7
|
+
.description("Inspect a registered agent")
|
|
8
|
+
.requiredOption("--id <agentId>", "Agent identifier")
|
|
9
|
+
.action(async (opts) => {
|
|
10
|
+
const spinner = ora("Fetching agent...").start();
|
|
11
|
+
try {
|
|
12
|
+
const contract = getContract();
|
|
13
|
+
const agent = await contract.getAgent(opts.id);
|
|
14
|
+
spinner.stop();
|
|
15
|
+
const statusColor = agent.active ? chalk.green("Active") : chalk.red("Frozen");
|
|
16
|
+
console.log(chalk.bold(`\nAgent: ${opts.id}\n`));
|
|
17
|
+
console.log(` Status: ${statusColor}`);
|
|
18
|
+
console.log(` Address: ${agent.agentAddress}`);
|
|
19
|
+
console.log(` ENS Node: ${agent.ensNode}`);
|
|
20
|
+
console.log(` Spend Limit: ${formatEther(agent.spendLimit)} ETH`);
|
|
21
|
+
console.log(` Threat Score: ${agent.threatScore}`);
|
|
22
|
+
console.log(` Strikes: ${agent.strikes}`);
|
|
23
|
+
console.log(` World ID: ${agent.worldIdVerified ? "Verified" : "Not verified"}`);
|
|
24
|
+
console.log(` Registered At: ${new Date(Number(agent.registeredAt) * 1000).toISOString()}`);
|
|
25
|
+
console.log();
|
|
26
|
+
}
|
|
27
|
+
catch (err) {
|
|
28
|
+
spinner.fail(chalk.red(`Failed to inspect agent: ${err.message}`));
|
|
29
|
+
process.exit(1);
|
|
30
|
+
}
|
|
31
|
+
});
|
|
32
|
+
//# sourceMappingURL=inspect.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"inspect.js","sourceRoot":"","sources":["../../src/commands/inspect.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,OAAO,EAAE,MAAM,WAAW,CAAC;AACpC,OAAO,KAAK,MAAM,OAAO,CAAC;AAC1B,OAAO,GAAG,MAAM,KAAK,CAAC;AACtB,OAAO,EAAE,WAAW,EAAE,MAAM,QAAQ,CAAC;AACrC,OAAO,EAAE,WAAW,EAAE,MAAM,cAAc,CAAC;AAE3C,MAAM,CAAC,MAAM,cAAc,GAAG,IAAI,OAAO,CAAC,SAAS,CAAC;KACjD,WAAW,CAAC,4BAA4B,CAAC;KACzC,cAAc,CAAC,gBAAgB,EAAE,kBAAkB,CAAC;KACpD,MAAM,CAAC,KAAK,EAAE,IAAI,EAAE,EAAE;IACrB,MAAM,OAAO,GAAG,GAAG,CAAC,mBAAmB,CAAC,CAAC,KAAK,EAAE,CAAC;IAEjD,IAAI,CAAC;QACH,MAAM,QAAQ,GAAG,WAAW,EAAE,CAAC;QAC/B,MAAM,KAAK,GAAG,MAAM,QAAQ,CAAC,QAAQ,CAAC,IAAI,CAAC,EAAE,CAAC,CAAC;QAE/C,OAAO,CAAC,IAAI,EAAE,CAAC;QAEf,MAAM,WAAW,GAAG,KAAK,CAAC,MAAM,CAAC,CAAC,CAAC,KAAK,CAAC,KAAK,CAAC,QAAQ,CAAC,CAAC,CAAC,CAAC,KAAK,CAAC,GAAG,CAAC,QAAQ,CAAC,CAAC;QAE/E,OAAO,CAAC,GAAG,CAAC,KAAK,CAAC,IAAI,CAAC,YAAY,IAAI,CAAC,EAAE,IAAI,CAAC,CAAC,CAAC;QACjD,OAAO,CAAC,GAAG,CAAC,sBAAsB,WAAW,EAAE,CAAC,CAAC;QACjD,OAAO,CAAC,GAAG,CAAC,sBAAsB,KAAK,CAAC,YAAY,EAAE,CAAC,CAAC;QACxD,OAAO,CAAC,GAAG,CAAC,sBAAsB,KAAK,CAAC,OAAO,EAAE,CAAC,CAAC;QACnD,OAAO,CAAC,GAAG,CAAC,sBAAsB,WAAW,CAAC,KAAK,CAAC,UAAU,CAAC,MAAM,CAAC,CAAC;QACvE,OAAO,CAAC,GAAG,CAAC,sBAAsB,KAAK,CAAC,WAAW,EAAE,CAAC,CAAC;QACvD,OAAO,CAAC,GAAG,CAAC,sBAAsB,KAAK,CAAC,OAAO,EAAE,CAAC,CAAC;QACnD,OAAO,CAAC,GAAG,CAAC,sBAAsB,KAAK,CAAC,eAAe,CAAC,CAAC,CAAC,UAAU,CAAC,CAAC,CAAC,cAAc,EAAE,CAAC,CAAC;QACzF,OAAO,CAAC,GAAG,CAAC,sBAAsB,IAAI,IAAI,CAAC,MAAM,CAAC,KAAK,CAAC,YAAY,CAAC,GAAG,IAAI,CAAC,CAAC,WAAW,EAAE,EAAE,CAAC,CAAC;QAC/F,OAAO,CAAC,GAAG,EAAE,CAAC;IAChB,CAAC;IAAC,OAAO,GAAQ,EAAE,CAAC;QAClB,OAAO,CAAC,IAAI,CAAC,KAAK,CAAC,GAAG,CAAC,4BAA4B,GAAG,CAAC,OAAO,EAAE,CAAC,CAAC,CAAC;QACnE,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;IAClB,CAAC;AACH,CAAC,CAAC,CAAC"}
|
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
import { Command } from "commander";
|
|
2
|
+
import chalk from "chalk";
|
|
3
|
+
import ora from "ora";
|
|
4
|
+
import { getContract } from "../config.js";
|
|
5
|
+
export const listCommand = new Command("list")
|
|
6
|
+
.description("List all registered agent IDs")
|
|
7
|
+
.action(async () => {
|
|
8
|
+
const spinner = ora("Fetching agents...").start();
|
|
9
|
+
try {
|
|
10
|
+
const contract = getContract();
|
|
11
|
+
const count = await contract.getAgentCount();
|
|
12
|
+
if (count === 0n) {
|
|
13
|
+
spinner.info("No agents registered.");
|
|
14
|
+
return;
|
|
15
|
+
}
|
|
16
|
+
const ids = [];
|
|
17
|
+
for (let i = 0n; i < count; i++) {
|
|
18
|
+
ids.push(await contract.agentIds(i));
|
|
19
|
+
}
|
|
20
|
+
spinner.stop();
|
|
21
|
+
console.log(chalk.bold(`\nRegistered agents (${count}):\n`));
|
|
22
|
+
for (const id of ids) {
|
|
23
|
+
console.log(` - ${id}`);
|
|
24
|
+
}
|
|
25
|
+
console.log();
|
|
26
|
+
}
|
|
27
|
+
catch (err) {
|
|
28
|
+
spinner.fail(chalk.red(`Failed to list agents: ${err.message}`));
|
|
29
|
+
process.exit(1);
|
|
30
|
+
}
|
|
31
|
+
});
|
|
32
|
+
//# sourceMappingURL=list.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"list.js","sourceRoot":"","sources":["../../src/commands/list.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,OAAO,EAAE,MAAM,WAAW,CAAC;AACpC,OAAO,KAAK,MAAM,OAAO,CAAC;AAC1B,OAAO,GAAG,MAAM,KAAK,CAAC;AACtB,OAAO,EAAE,WAAW,EAAE,MAAM,cAAc,CAAC;AAE3C,MAAM,CAAC,MAAM,WAAW,GAAG,IAAI,OAAO,CAAC,MAAM,CAAC;KAC3C,WAAW,CAAC,+BAA+B,CAAC;KAC5C,MAAM,CAAC,KAAK,IAAI,EAAE;IACjB,MAAM,OAAO,GAAG,GAAG,CAAC,oBAAoB,CAAC,CAAC,KAAK,EAAE,CAAC;IAElD,IAAI,CAAC;QACH,MAAM,QAAQ,GAAG,WAAW,EAAE,CAAC;QAC/B,MAAM,KAAK,GAAG,MAAM,QAAQ,CAAC,aAAa,EAAE,CAAC;QAE7C,IAAI,KAAK,KAAK,EAAE,EAAE,CAAC;YACjB,OAAO,CAAC,IAAI,CAAC,uBAAuB,CAAC,CAAC;YACtC,OAAO;QACT,CAAC;QAED,MAAM,GAAG,GAAa,EAAE,CAAC;QACzB,KAAK,IAAI,CAAC,GAAG,EAAE,EAAE,CAAC,GAAG,KAAK,EAAE,CAAC,EAAE,EAAE,CAAC;YAChC,GAAG,CAAC,IAAI,CAAC,MAAM,QAAQ,CAAC,QAAQ,CAAC,CAAC,CAAC,CAAC,CAAC;QACvC,CAAC;QAED,OAAO,CAAC,IAAI,EAAE,CAAC;QACf,OAAO,CAAC,GAAG,CAAC,KAAK,CAAC,IAAI,CAAC,wBAAwB,KAAK,MAAM,CAAC,CAAC,CAAC;QAC7D,KAAK,MAAM,EAAE,IAAI,GAAG,EAAE,CAAC;YACrB,OAAO,CAAC,GAAG,CAAC,OAAO,EAAE,EAAE,CAAC,CAAC;QAC3B,CAAC;QACD,OAAO,CAAC,GAAG,EAAE,CAAC;IAChB,CAAC;IAAC,OAAO,GAAQ,EAAE,CAAC;QAClB,OAAO,CAAC,IAAI,CAAC,KAAK,CAAC,GAAG,CAAC,0BAA0B,GAAG,CAAC,OAAO,EAAE,CAAC,CAAC,CAAC;QACjE,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;IAClB,CAAC;AACH,CAAC,CAAC,CAAC"}
|
|
@@ -0,0 +1,54 @@
|
|
|
1
|
+
import { Command } from "commander";
|
|
2
|
+
import chalk from "chalk";
|
|
3
|
+
import ora from "ora";
|
|
4
|
+
import { ENShell, Network, ActionDecision } from "@enshell/sdk";
|
|
5
|
+
import { getSigner } from "../config.js";
|
|
6
|
+
export const protectCommand = new Command("protect")
|
|
7
|
+
.description("Submit an action through the ENShell firewall with encryption and relay")
|
|
8
|
+
.requiredOption("--id <agentId>", "Agent identifier")
|
|
9
|
+
.requiredOption("--target <address>", "Target contract address")
|
|
10
|
+
.requiredOption("--value <eth>", "Value in ETH")
|
|
11
|
+
.option("--data <hex>", "Calldata (hex)", "0x")
|
|
12
|
+
.requiredOption("--instruction <text>", "Human-readable instruction")
|
|
13
|
+
.action(async (opts) => {
|
|
14
|
+
try {
|
|
15
|
+
const signer = await getSigner();
|
|
16
|
+
const client = new ENShell({
|
|
17
|
+
network: Network.SEPOLIA,
|
|
18
|
+
signer,
|
|
19
|
+
});
|
|
20
|
+
// Step 1: Encrypt + relay + submit
|
|
21
|
+
const submitSpinner = ora("Encrypting instruction and submitting action...").start();
|
|
22
|
+
const result = await client.protect(opts.id, {
|
|
23
|
+
instruction: opts.instruction,
|
|
24
|
+
tx: {
|
|
25
|
+
to: opts.target,
|
|
26
|
+
value: opts.value,
|
|
27
|
+
data: opts.data,
|
|
28
|
+
},
|
|
29
|
+
});
|
|
30
|
+
submitSpinner.succeed(chalk.green(`Action #${result.actionId} queued (hash: ${result.instructionHash.slice(0, 18)}...)`));
|
|
31
|
+
console.log(chalk.gray(` tx: https://sepolia.etherscan.io/tx/${result.txHash}`));
|
|
32
|
+
// Step 2: Wait for CRE resolution
|
|
33
|
+
const waitSpinner = ora("Waiting for CRE oracle resolution...").start();
|
|
34
|
+
const decision = await result.waitForResolution();
|
|
35
|
+
switch (decision) {
|
|
36
|
+
case ActionDecision.APPROVED:
|
|
37
|
+
waitSpinner.succeed(chalk.green("Action approved by CRE oracle"));
|
|
38
|
+
break;
|
|
39
|
+
case ActionDecision.ESCALATED:
|
|
40
|
+
waitSpinner.warn(chalk.yellow("Action escalated - waiting for Ledger approval..."));
|
|
41
|
+
break;
|
|
42
|
+
case ActionDecision.BLOCKED:
|
|
43
|
+
waitSpinner.fail(chalk.red("Action blocked by CRE oracle"));
|
|
44
|
+
break;
|
|
45
|
+
default:
|
|
46
|
+
waitSpinner.info(`Decision: ${decision}`);
|
|
47
|
+
}
|
|
48
|
+
}
|
|
49
|
+
catch (err) {
|
|
50
|
+
console.error(chalk.red(`\nProtect failed: ${err.message}`));
|
|
51
|
+
process.exit(1);
|
|
52
|
+
}
|
|
53
|
+
});
|
|
54
|
+
//# sourceMappingURL=protect.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"protect.js","sourceRoot":"","sources":["../../src/commands/protect.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,OAAO,EAAE,MAAM,WAAW,CAAC;AACpC,OAAO,KAAK,MAAM,OAAO,CAAC;AAC1B,OAAO,GAAG,MAAM,KAAK,CAAC;AACtB,OAAO,EAAE,OAAO,EAAE,OAAO,EAAE,cAAc,EAAE,MAAM,cAAc,CAAC;AAChE,OAAO,EAAE,SAAS,EAAE,MAAM,cAAc,CAAC;AAEzC,MAAM,CAAC,MAAM,cAAc,GAAG,IAAI,OAAO,CAAC,SAAS,CAAC;KACjD,WAAW,CAAC,yEAAyE,CAAC;KACtF,cAAc,CAAC,gBAAgB,EAAE,kBAAkB,CAAC;KACpD,cAAc,CAAC,oBAAoB,EAAE,yBAAyB,CAAC;KAC/D,cAAc,CAAC,eAAe,EAAE,cAAc,CAAC;KAC/C,MAAM,CAAC,cAAc,EAAE,gBAAgB,EAAE,IAAI,CAAC;KAC9C,cAAc,CAAC,sBAAsB,EAAE,4BAA4B,CAAC;KACpE,MAAM,CAAC,KAAK,EAAE,IAAI,EAAE,EAAE;IACrB,IAAI,CAAC;QACH,MAAM,MAAM,GAAG,MAAM,SAAS,EAAE,CAAC;QACjC,MAAM,MAAM,GAAG,IAAI,OAAO,CAAC;YACzB,OAAO,EAAE,OAAO,CAAC,OAAO;YACxB,MAAM;SACP,CAAC,CAAC;QAEH,mCAAmC;QACnC,MAAM,aAAa,GAAG,GAAG,CAAC,iDAAiD,CAAC,CAAC,KAAK,EAAE,CAAC;QACrF,MAAM,MAAM,GAAG,MAAM,MAAM,CAAC,OAAO,CAAC,IAAI,CAAC,EAAE,EAAE;YAC3C,WAAW,EAAE,IAAI,CAAC,WAAW;YAC7B,EAAE,EAAE;gBACF,EAAE,EAAE,IAAI,CAAC,MAAM;gBACf,KAAK,EAAE,IAAI,CAAC,KAAK;gBACjB,IAAI,EAAE,IAAI,CAAC,IAAI;aAChB;SACF,CAAC,CAAC;QACH,aAAa,CAAC,OAAO,CACnB,KAAK,CAAC,KAAK,CAAC,WAAW,MAAM,CAAC,QAAQ,kBAAkB,MAAM,CAAC,eAAe,CAAC,KAAK,CAAC,CAAC,EAAE,EAAE,CAAC,MAAM,CAAC,CACnG,CAAC;QACF,OAAO,CAAC,GAAG,CAAC,KAAK,CAAC,IAAI,CAAC,yCAAyC,MAAM,CAAC,MAAM,EAAE,CAAC,CAAC,CAAC;QAElF,kCAAkC;QAClC,MAAM,WAAW,GAAG,GAAG,CAAC,sCAAsC,CAAC,CAAC,KAAK,EAAE,CAAC;QACxE,MAAM,QAAQ,GAAG,MAAM,MAAM,CAAC,iBAAiB,EAAE,CAAC;QAElD,QAAQ,QAAQ,EAAE,CAAC;YACjB,KAAK,cAAc,CAAC,QAAQ;gBAC1B,WAAW,CAAC,OAAO,CAAC,KAAK,CAAC,KAAK,CAAC,+BAA+B,CAAC,CAAC,CAAC;gBAClE,MAAM;YACR,KAAK,cAAc,CAAC,SAAS;gBAC3B,WAAW,CAAC,IAAI,CAAC,KAAK,CAAC,MAAM,CAAC,mDAAmD,CAAC,CAAC,CAAC;gBACpF,MAAM;YACR,KAAK,cAAc,CAAC,OAAO;gBACzB,WAAW,CAAC,IAAI,CAAC,KAAK,CAAC,GAAG,CAAC,8BAA8B,CAAC,CAAC,CAAC;gBAC5D,MAAM;YACR;gBACE,WAAW,CAAC,IAAI,CAAC,aAAa,QAAQ,EAAE,CAAC,CAAC;QAC9C,CAAC;IACH,CAAC;IAAC,OAAO,GAAQ,EAAE,CAAC;QAClB,OAAO,CAAC,KAAK,CAAC,KAAK,CAAC,GAAG,CAAC,qBAAqB,GAAG,CAAC,OAAO,EAAE,CAAC,CAAC,CAAC;QAC7D,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;IAClB,CAAC;AACH,CAAC,CAAC,CAAC"}
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
import { Command } from "commander";
|
|
2
|
+
import chalk from "chalk";
|
|
3
|
+
import ora from "ora";
|
|
4
|
+
import { ENShell, Network } from "@enshell/sdk";
|
|
5
|
+
import { getSigner } from "../config.js";
|
|
6
|
+
export const reactivateCommand = new Command("reactivate")
|
|
7
|
+
.description("Reactivate a frozen agent")
|
|
8
|
+
.requiredOption("--id <agentId>", "Agent identifier")
|
|
9
|
+
.action(async (opts) => {
|
|
10
|
+
const spinner = ora("Reactivating agent...").start();
|
|
11
|
+
try {
|
|
12
|
+
const signer = await getSigner();
|
|
13
|
+
const client = new ENShell({
|
|
14
|
+
network: Network.SEPOLIA,
|
|
15
|
+
signer,
|
|
16
|
+
});
|
|
17
|
+
const { txHash } = await client.reactivateAgent(opts.id);
|
|
18
|
+
spinner.succeed(chalk.green(`Agent "${opts.id}" reactivated`));
|
|
19
|
+
console.log(chalk.gray(` tx: https://sepolia.etherscan.io/tx/${txHash}`));
|
|
20
|
+
}
|
|
21
|
+
catch (err) {
|
|
22
|
+
spinner.fail(chalk.red(`Reactivation failed: ${err.message}`));
|
|
23
|
+
process.exit(1);
|
|
24
|
+
}
|
|
25
|
+
});
|
|
26
|
+
//# sourceMappingURL=reactivate.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"reactivate.js","sourceRoot":"","sources":["../../src/commands/reactivate.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,OAAO,EAAE,MAAM,WAAW,CAAC;AACpC,OAAO,KAAK,MAAM,OAAO,CAAC;AAC1B,OAAO,GAAG,MAAM,KAAK,CAAC;AACtB,OAAO,EAAE,OAAO,EAAE,OAAO,EAAE,MAAM,cAAc,CAAC;AAChD,OAAO,EAAE,SAAS,EAAE,MAAM,cAAc,CAAC;AAEzC,MAAM,CAAC,MAAM,iBAAiB,GAAG,IAAI,OAAO,CAAC,YAAY,CAAC;KACvD,WAAW,CAAC,2BAA2B,CAAC;KACxC,cAAc,CAAC,gBAAgB,EAAE,kBAAkB,CAAC;KACpD,MAAM,CAAC,KAAK,EAAE,IAAI,EAAE,EAAE;IACrB,MAAM,OAAO,GAAG,GAAG,CAAC,uBAAuB,CAAC,CAAC,KAAK,EAAE,CAAC;IAErD,IAAI,CAAC;QACH,MAAM,MAAM,GAAG,MAAM,SAAS,EAAE,CAAC;QACjC,MAAM,MAAM,GAAG,IAAI,OAAO,CAAC;YACzB,OAAO,EAAE,OAAO,CAAC,OAAO;YACxB,MAAM;SACP,CAAC,CAAC;QAEH,MAAM,EAAE,MAAM,EAAE,GAAG,MAAM,MAAM,CAAC,eAAe,CAAC,IAAI,CAAC,EAAE,CAAC,CAAC;QAEzD,OAAO,CAAC,OAAO,CAAC,KAAK,CAAC,KAAK,CAAC,UAAU,IAAI,CAAC,EAAE,eAAe,CAAC,CAAC,CAAC;QAC/D,OAAO,CAAC,GAAG,CAAC,KAAK,CAAC,IAAI,CAAC,yCAAyC,MAAM,EAAE,CAAC,CAAC,CAAC;IAC7E,CAAC;IAAC,OAAO,GAAQ,EAAE,CAAC;QAClB,OAAO,CAAC,IAAI,CAAC,KAAK,CAAC,GAAG,CAAC,wBAAwB,GAAG,CAAC,OAAO,EAAE,CAAC,CAAC,CAAC;QAC/D,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;IAClB,CAAC;AACH,CAAC,CAAC,CAAC"}
|
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
import { Command } from "commander";
|
|
2
|
+
import chalk from "chalk";
|
|
3
|
+
import ora from "ora";
|
|
4
|
+
import { ENShell, Network } from "@enshell/sdk";
|
|
5
|
+
import { getSigner } from "../config.js";
|
|
6
|
+
export const registerCommand = new Command("register")
|
|
7
|
+
.description("Register a new AI agent on the firewall")
|
|
8
|
+
.requiredOption("--id <agentId>", "Unique agent identifier (becomes <id>.enshell.eth)")
|
|
9
|
+
.requiredOption("--agent-wallet <address>", "Agent's wallet address")
|
|
10
|
+
.requiredOption("--spend-limit <limit>", "Spend limit in ETH")
|
|
11
|
+
.option("--targets <addresses...>", "Allowed target addresses")
|
|
12
|
+
.action(async (opts) => {
|
|
13
|
+
try {
|
|
14
|
+
const signer = await getSigner();
|
|
15
|
+
const client = new ENShell({
|
|
16
|
+
network: Network.SEPOLIA,
|
|
17
|
+
signer,
|
|
18
|
+
});
|
|
19
|
+
const spinner = ora(`Registering agent "${opts.id}" (creates ${opts.id}.enshell.eth)...`).start();
|
|
20
|
+
const result = await client.registerAgent(opts.id, {
|
|
21
|
+
agentAddress: opts.agentWallet,
|
|
22
|
+
spendLimit: opts.spendLimit,
|
|
23
|
+
allowedTargets: opts.targets,
|
|
24
|
+
});
|
|
25
|
+
spinner.succeed(chalk.green(`Agent "${opts.id}" registered as ${opts.id}.enshell.eth`));
|
|
26
|
+
console.log(chalk.gray(` tx: https://sepolia.etherscan.io/tx/${result.txHash}`));
|
|
27
|
+
}
|
|
28
|
+
catch (err) {
|
|
29
|
+
console.error(chalk.red(`\nRegistration failed: ${err.message}`));
|
|
30
|
+
process.exit(1);
|
|
31
|
+
}
|
|
32
|
+
});
|
|
33
|
+
//# sourceMappingURL=register.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"register.js","sourceRoot":"","sources":["../../src/commands/register.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,OAAO,EAAE,MAAM,WAAW,CAAC;AACpC,OAAO,KAAK,MAAM,OAAO,CAAC;AAC1B,OAAO,GAAG,MAAM,KAAK,CAAC;AACtB,OAAO,EAAE,OAAO,EAAE,OAAO,EAAE,MAAM,cAAc,CAAC;AAChD,OAAO,EAAE,SAAS,EAAE,MAAM,cAAc,CAAC;AAEzC,MAAM,CAAC,MAAM,eAAe,GAAG,IAAI,OAAO,CAAC,UAAU,CAAC;KACnD,WAAW,CAAC,yCAAyC,CAAC;KACtD,cAAc,CAAC,gBAAgB,EAAE,oDAAoD,CAAC;KACtF,cAAc,CAAC,0BAA0B,EAAE,wBAAwB,CAAC;KACpE,cAAc,CAAC,uBAAuB,EAAE,oBAAoB,CAAC;KAC7D,MAAM,CAAC,0BAA0B,EAAE,0BAA0B,CAAC;KAC9D,MAAM,CAAC,KAAK,EAAE,IAAI,EAAE,EAAE;IACrB,IAAI,CAAC;QACH,MAAM,MAAM,GAAG,MAAM,SAAS,EAAE,CAAC;QACjC,MAAM,MAAM,GAAG,IAAI,OAAO,CAAC;YACzB,OAAO,EAAE,OAAO,CAAC,OAAO;YACxB,MAAM;SACP,CAAC,CAAC;QAEH,MAAM,OAAO,GAAG,GAAG,CAAC,sBAAsB,IAAI,CAAC,EAAE,cAAc,IAAI,CAAC,EAAE,kBAAkB,CAAC,CAAC,KAAK,EAAE,CAAC;QAClG,MAAM,MAAM,GAAG,MAAM,MAAM,CAAC,aAAa,CAAC,IAAI,CAAC,EAAE,EAAE;YACjD,YAAY,EAAE,IAAI,CAAC,WAAW;YAC9B,UAAU,EAAE,IAAI,CAAC,UAAU;YAC3B,cAAc,EAAE,IAAI,CAAC,OAAO;SAC7B,CAAC,CAAC;QACH,OAAO,CAAC,OAAO,CAAC,KAAK,CAAC,KAAK,CAAC,UAAU,IAAI,CAAC,EAAE,mBAAmB,IAAI,CAAC,EAAE,cAAc,CAAC,CAAC,CAAC;QACxF,OAAO,CAAC,GAAG,CAAC,KAAK,CAAC,IAAI,CAAC,yCAAyC,MAAM,CAAC,MAAM,EAAE,CAAC,CAAC,CAAC;IACpF,CAAC;IAAC,OAAO,GAAQ,EAAE,CAAC;QAClB,OAAO,CAAC,KAAK,CAAC,KAAK,CAAC,GAAG,CAAC,0BAA0B,GAAG,CAAC,OAAO,EAAE,CAAC,CAAC,CAAC;QAClE,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;IAClB,CAAC;AACH,CAAC,CAAC,CAAC"}
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
import { Command } from "commander";
|
|
2
|
+
import chalk from "chalk";
|
|
3
|
+
import ora from "ora";
|
|
4
|
+
import { ENShell, Network } from "@enshell/sdk";
|
|
5
|
+
import { getSigner } from "../config.js";
|
|
6
|
+
export const rejectCommand = new Command("reject")
|
|
7
|
+
.description("Reject a queued action")
|
|
8
|
+
.requiredOption("--action-id <id>", "Queued action ID")
|
|
9
|
+
.action(async (opts) => {
|
|
10
|
+
const spinner = ora("Rejecting action...").start();
|
|
11
|
+
try {
|
|
12
|
+
const signer = await getSigner();
|
|
13
|
+
const client = new ENShell({
|
|
14
|
+
network: Network.SEPOLIA,
|
|
15
|
+
signer,
|
|
16
|
+
});
|
|
17
|
+
const { txHash } = await client.rejectAction(BigInt(opts.actionId));
|
|
18
|
+
spinner.succeed(chalk.green(`Action #${opts.actionId} rejected`));
|
|
19
|
+
console.log(chalk.gray(` tx: https://sepolia.etherscan.io/tx/${txHash}`));
|
|
20
|
+
}
|
|
21
|
+
catch (err) {
|
|
22
|
+
spinner.fail(chalk.red(`Rejection failed: ${err.message}`));
|
|
23
|
+
process.exit(1);
|
|
24
|
+
}
|
|
25
|
+
});
|
|
26
|
+
//# sourceMappingURL=reject.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"reject.js","sourceRoot":"","sources":["../../src/commands/reject.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,OAAO,EAAE,MAAM,WAAW,CAAC;AACpC,OAAO,KAAK,MAAM,OAAO,CAAC;AAC1B,OAAO,GAAG,MAAM,KAAK,CAAC;AACtB,OAAO,EAAE,OAAO,EAAE,OAAO,EAAE,MAAM,cAAc,CAAC;AAChD,OAAO,EAAE,SAAS,EAAE,MAAM,cAAc,CAAC;AAEzC,MAAM,CAAC,MAAM,aAAa,GAAG,IAAI,OAAO,CAAC,QAAQ,CAAC;KAC/C,WAAW,CAAC,wBAAwB,CAAC;KACrC,cAAc,CAAC,kBAAkB,EAAE,kBAAkB,CAAC;KACtD,MAAM,CAAC,KAAK,EAAE,IAAI,EAAE,EAAE;IACrB,MAAM,OAAO,GAAG,GAAG,CAAC,qBAAqB,CAAC,CAAC,KAAK,EAAE,CAAC;IAEnD,IAAI,CAAC;QACH,MAAM,MAAM,GAAG,MAAM,SAAS,EAAE,CAAC;QACjC,MAAM,MAAM,GAAG,IAAI,OAAO,CAAC;YACzB,OAAO,EAAE,OAAO,CAAC,OAAO;YACxB,MAAM;SACP,CAAC,CAAC;QAEH,MAAM,EAAE,MAAM,EAAE,GAAG,MAAM,MAAM,CAAC,YAAY,CAAC,MAAM,CAAC,IAAI,CAAC,QAAQ,CAAC,CAAC,CAAC;QAEpE,OAAO,CAAC,OAAO,CAAC,KAAK,CAAC,KAAK,CAAC,WAAW,IAAI,CAAC,QAAQ,WAAW,CAAC,CAAC,CAAC;QAClE,OAAO,CAAC,GAAG,CAAC,KAAK,CAAC,IAAI,CAAC,yCAAyC,MAAM,EAAE,CAAC,CAAC,CAAC;IAC7E,CAAC;IAAC,OAAO,GAAQ,EAAE,CAAC;QAClB,OAAO,CAAC,IAAI,CAAC,KAAK,CAAC,GAAG,CAAC,qBAAqB,GAAG,CAAC,OAAO,EAAE,CAAC,CAAC,CAAC;QAC5D,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;IAClB,CAAC;AACH,CAAC,CAAC,CAAC"}
|
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
import { Command } from "commander";
|
|
2
|
+
import { keccak256, toUtf8Bytes } from "ethers";
|
|
3
|
+
import chalk from "chalk";
|
|
4
|
+
import ora from "ora";
|
|
5
|
+
import { ENShell, Network } from "@enshell/sdk";
|
|
6
|
+
import { getSigner } from "../config.js";
|
|
7
|
+
export const submitCommand = new Command("submit")
|
|
8
|
+
.description("Submit an action through the firewall (queued for CRE analysis)")
|
|
9
|
+
.requiredOption("--id <agentId>", "Agent identifier")
|
|
10
|
+
.requiredOption("--target <address>", "Target contract address")
|
|
11
|
+
.requiredOption("--value <eth>", "Value in ETH")
|
|
12
|
+
.option("--data <hex>", "Calldata (hex)", "0x")
|
|
13
|
+
.requiredOption("--instruction <text>", "Human-readable instruction")
|
|
14
|
+
.action(async (opts) => {
|
|
15
|
+
const spinner = ora("Submitting action...").start();
|
|
16
|
+
try {
|
|
17
|
+
const signer = await getSigner();
|
|
18
|
+
const client = new ENShell({
|
|
19
|
+
network: Network.SEPOLIA,
|
|
20
|
+
signer,
|
|
21
|
+
});
|
|
22
|
+
const instructionHash = keccak256(toUtf8Bytes(opts.instruction));
|
|
23
|
+
const result = await client.submitAction(opts.id, opts.target, opts.value, opts.data, instructionHash);
|
|
24
|
+
spinner.succeed(chalk.green(`Action #${result.actionId} queued for CRE analysis`));
|
|
25
|
+
console.log(chalk.gray(` tx: https://sepolia.etherscan.io/tx/${result.txHash}`));
|
|
26
|
+
}
|
|
27
|
+
catch (err) {
|
|
28
|
+
spinner.fail(chalk.red(`Submission failed: ${err.message}`));
|
|
29
|
+
process.exit(1);
|
|
30
|
+
}
|
|
31
|
+
});
|
|
32
|
+
//# sourceMappingURL=submit.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"submit.js","sourceRoot":"","sources":["../../src/commands/submit.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,OAAO,EAAE,MAAM,WAAW,CAAC;AACpC,OAAO,EAAE,SAAS,EAAE,WAAW,EAAE,MAAM,QAAQ,CAAC;AAChD,OAAO,KAAK,MAAM,OAAO,CAAC;AAC1B,OAAO,GAAG,MAAM,KAAK,CAAC;AACtB,OAAO,EAAE,OAAO,EAAE,OAAO,EAAE,MAAM,cAAc,CAAC;AAChD,OAAO,EAAE,SAAS,EAAE,MAAM,cAAc,CAAC;AAEzC,MAAM,CAAC,MAAM,aAAa,GAAG,IAAI,OAAO,CAAC,QAAQ,CAAC;KAC/C,WAAW,CAAC,iEAAiE,CAAC;KAC9E,cAAc,CAAC,gBAAgB,EAAE,kBAAkB,CAAC;KACpD,cAAc,CAAC,oBAAoB,EAAE,yBAAyB,CAAC;KAC/D,cAAc,CAAC,eAAe,EAAE,cAAc,CAAC;KAC/C,MAAM,CAAC,cAAc,EAAE,gBAAgB,EAAE,IAAI,CAAC;KAC9C,cAAc,CAAC,sBAAsB,EAAE,4BAA4B,CAAC;KACpE,MAAM,CAAC,KAAK,EAAE,IAAI,EAAE,EAAE;IACrB,MAAM,OAAO,GAAG,GAAG,CAAC,sBAAsB,CAAC,CAAC,KAAK,EAAE,CAAC;IAEpD,IAAI,CAAC;QACH,MAAM,MAAM,GAAG,MAAM,SAAS,EAAE,CAAC;QACjC,MAAM,MAAM,GAAG,IAAI,OAAO,CAAC;YACzB,OAAO,EAAE,OAAO,CAAC,OAAO;YACxB,MAAM;SACP,CAAC,CAAC;QAEH,MAAM,eAAe,GAAG,SAAS,CAAC,WAAW,CAAC,IAAI,CAAC,WAAW,CAAC,CAAC,CAAC;QAEjE,MAAM,MAAM,GAAG,MAAM,MAAM,CAAC,YAAY,CACtC,IAAI,CAAC,EAAE,EACP,IAAI,CAAC,MAAM,EACX,IAAI,CAAC,KAAK,EACV,IAAI,CAAC,IAAI,EACT,eAAe,CAChB,CAAC;QAEF,OAAO,CAAC,OAAO,CACb,KAAK,CAAC,KAAK,CAAC,WAAW,MAAM,CAAC,QAAQ,0BAA0B,CAAC,CAClE,CAAC;QACF,OAAO,CAAC,GAAG,CAAC,KAAK,CAAC,IAAI,CAAC,yCAAyC,MAAM,CAAC,MAAM,EAAE,CAAC,CAAC,CAAC;IACpF,CAAC;IAAC,OAAO,GAAQ,EAAE,CAAC;QAClB,OAAO,CAAC,IAAI,CAAC,KAAK,CAAC,GAAG,CAAC,sBAAsB,GAAG,CAAC,OAAO,EAAE,CAAC,CAAC,CAAC;QAC7D,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;IAClB,CAAC;AACH,CAAC,CAAC,CAAC"}
|
package/dist/config.d.ts
ADDED
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
import "dotenv/config";
|
|
2
|
+
import { JsonRpcProvider, Signer } from "ethers";
|
|
3
|
+
import { WalletMode } from "./wallets/index.js";
|
|
4
|
+
export declare function setWalletMode(mode: WalletMode): void;
|
|
5
|
+
export declare function getWalletMode(): WalletMode;
|
|
6
|
+
export declare function getProvider(): JsonRpcProvider;
|
|
7
|
+
export declare function getSigner(): Promise<Signer>;
|
|
8
|
+
export declare function getContractAddress(): string;
|
|
9
|
+
/** Read-only contract instance (no signer needed). */
|
|
10
|
+
export declare function getContract(): import("ethers").Contract;
|
package/dist/config.js
ADDED
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
import "dotenv/config";
|
|
2
|
+
import { JsonRpcProvider } from "ethers";
|
|
3
|
+
import { getFirewallContract } from "@enshell/sdk";
|
|
4
|
+
import { resolveSigner } from "./wallets/index.js";
|
|
5
|
+
/** Global wallet mode — set by --wallet flag in index.ts */
|
|
6
|
+
let _walletMode = "walletconnect";
|
|
7
|
+
export function setWalletMode(mode) {
|
|
8
|
+
_walletMode = mode;
|
|
9
|
+
}
|
|
10
|
+
export function getWalletMode() {
|
|
11
|
+
return _walletMode;
|
|
12
|
+
}
|
|
13
|
+
export function getProvider() {
|
|
14
|
+
const rpcUrl = process.env.ENSHELL_RPC_URL || "https://rpc.sepolia.org";
|
|
15
|
+
return new JsonRpcProvider(rpcUrl);
|
|
16
|
+
}
|
|
17
|
+
export async function getSigner() {
|
|
18
|
+
return resolveSigner(_walletMode);
|
|
19
|
+
}
|
|
20
|
+
export function getContractAddress() {
|
|
21
|
+
const addr = process.env.ENSHELL_CONTRACT_ADDRESS;
|
|
22
|
+
if (!addr)
|
|
23
|
+
return "0xeb91387Ea4B7ADF8fA4901B22B2B72d7c54cbF13"; // Sepolia default
|
|
24
|
+
return addr;
|
|
25
|
+
}
|
|
26
|
+
/** Read-only contract instance (no signer needed). */
|
|
27
|
+
export function getContract() {
|
|
28
|
+
return getFirewallContract(getContractAddress(), getProvider());
|
|
29
|
+
}
|
|
30
|
+
//# sourceMappingURL=config.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"config.js","sourceRoot":"","sources":["../src/config.ts"],"names":[],"mappings":"AAAA,OAAO,eAAe,CAAC;AACvB,OAAO,EAAE,eAAe,EAAU,MAAM,QAAQ,CAAC;AACjD,OAAO,EAAE,mBAAmB,EAAE,MAAM,cAAc,CAAC;AACnD,OAAO,EAAE,aAAa,EAAc,MAAM,oBAAoB,CAAC;AAE/D,4DAA4D;AAC5D,IAAI,WAAW,GAAe,eAAe,CAAC;AAE9C,MAAM,UAAU,aAAa,CAAC,IAAgB;IAC5C,WAAW,GAAG,IAAI,CAAC;AACrB,CAAC;AAED,MAAM,UAAU,aAAa;IAC3B,OAAO,WAAW,CAAC;AACrB,CAAC;AAED,MAAM,UAAU,WAAW;IACzB,MAAM,MAAM,GAAG,OAAO,CAAC,GAAG,CAAC,eAAe,IAAI,yBAAyB,CAAC;IACxE,OAAO,IAAI,eAAe,CAAC,MAAM,CAAC,CAAC;AACrC,CAAC;AAED,MAAM,CAAC,KAAK,UAAU,SAAS;IAC7B,OAAO,aAAa,CAAC,WAAW,CAAC,CAAC;AACpC,CAAC;AAED,MAAM,UAAU,kBAAkB;IAChC,MAAM,IAAI,GAAG,OAAO,CAAC,GAAG,CAAC,wBAAwB,CAAC;IAClD,IAAI,CAAC,IAAI;QACP,OAAO,4CAA4C,CAAC,CAAC,kBAAkB;IACzE,OAAO,IAAI,CAAC;AACd,CAAC;AAED,sDAAsD;AACtD,MAAM,UAAU,WAAW;IACzB,OAAO,mBAAmB,CAAC,kBAAkB,EAAE,EAAE,WAAW,EAAE,CAAC,CAAC;AAClE,CAAC"}
|
package/dist/index.d.ts
ADDED
package/dist/index.js
ADDED
|
@@ -0,0 +1,39 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
import { Command } from "commander";
|
|
3
|
+
import { setWalletMode } from "./config.js";
|
|
4
|
+
import { registerCommand } from "./commands/register.js";
|
|
5
|
+
import { listCommand } from "./commands/list.js";
|
|
6
|
+
import { inspectCommand } from "./commands/inspect.js";
|
|
7
|
+
import { submitCommand } from "./commands/submit.js";
|
|
8
|
+
import { approveCommand } from "./commands/approve.js";
|
|
9
|
+
import { rejectCommand } from "./commands/reject.js";
|
|
10
|
+
import { deactivateCommand } from "./commands/deactivate.js";
|
|
11
|
+
import { reactivateCommand } from "./commands/reactivate.js";
|
|
12
|
+
import { protectCommand } from "./commands/protect.js";
|
|
13
|
+
import { connectCommand } from "./commands/connect.js";
|
|
14
|
+
import { disconnectCommand } from "./commands/disconnect.js";
|
|
15
|
+
const program = new Command();
|
|
16
|
+
program
|
|
17
|
+
.name("enshell")
|
|
18
|
+
.description("CLI for ENShell on-chain AI agent firewall")
|
|
19
|
+
.version("0.1.0")
|
|
20
|
+
.option("--wallet <mode>", "Wallet mode: env (private key) or ledger (USB)")
|
|
21
|
+
.hook("preAction", (thisCommand) => {
|
|
22
|
+
const opts = thisCommand.opts();
|
|
23
|
+
if (opts.wallet) {
|
|
24
|
+
setWalletMode(opts.wallet);
|
|
25
|
+
}
|
|
26
|
+
});
|
|
27
|
+
program.addCommand(connectCommand);
|
|
28
|
+
program.addCommand(disconnectCommand);
|
|
29
|
+
program.addCommand(registerCommand);
|
|
30
|
+
program.addCommand(listCommand);
|
|
31
|
+
program.addCommand(inspectCommand);
|
|
32
|
+
program.addCommand(submitCommand);
|
|
33
|
+
program.addCommand(approveCommand);
|
|
34
|
+
program.addCommand(rejectCommand);
|
|
35
|
+
program.addCommand(deactivateCommand);
|
|
36
|
+
program.addCommand(reactivateCommand);
|
|
37
|
+
program.addCommand(protectCommand);
|
|
38
|
+
program.parseAsync().then(() => process.exit(0));
|
|
39
|
+
//# sourceMappingURL=index.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":";AACA,OAAO,EAAE,OAAO,EAAE,MAAM,WAAW,CAAC;AACpC,OAAO,EAAE,aAAa,EAAE,MAAM,aAAa,CAAC;AAE5C,OAAO,EAAE,eAAe,EAAE,MAAM,wBAAwB,CAAC;AACzD,OAAO,EAAE,WAAW,EAAE,MAAM,oBAAoB,CAAC;AACjD,OAAO,EAAE,cAAc,EAAE,MAAM,uBAAuB,CAAC;AACvD,OAAO,EAAE,aAAa,EAAE,MAAM,sBAAsB,CAAC;AACrD,OAAO,EAAE,cAAc,EAAE,MAAM,uBAAuB,CAAC;AACvD,OAAO,EAAE,aAAa,EAAE,MAAM,sBAAsB,CAAC;AACrD,OAAO,EAAE,iBAAiB,EAAE,MAAM,0BAA0B,CAAC;AAC7D,OAAO,EAAE,iBAAiB,EAAE,MAAM,0BAA0B,CAAC;AAC7D,OAAO,EAAE,cAAc,EAAE,MAAM,uBAAuB,CAAC;AACvD,OAAO,EAAE,cAAc,EAAE,MAAM,uBAAuB,CAAC;AACvD,OAAO,EAAE,iBAAiB,EAAE,MAAM,0BAA0B,CAAC;AAE7D,MAAM,OAAO,GAAG,IAAI,OAAO,EAAE,CAAC;AAE9B,OAAO;KACJ,IAAI,CAAC,SAAS,CAAC;KACf,WAAW,CAAC,4CAA4C,CAAC;KACzD,OAAO,CAAC,OAAO,CAAC;KAChB,MAAM,CACL,iBAAiB,EACjB,gDAAgD,CACjD;KACA,IAAI,CAAC,WAAW,EAAE,CAAC,WAAW,EAAE,EAAE;IACjC,MAAM,IAAI,GAAG,WAAW,CAAC,IAAI,EAAE,CAAC;IAChC,IAAI,IAAI,CAAC,MAAM,EAAE,CAAC;QAChB,aAAa,CAAC,IAAI,CAAC,MAAoB,CAAC,CAAC;IAC3C,CAAC;AACH,CAAC,CAAC,CAAC;AAEL,OAAO,CAAC,UAAU,CAAC,cAAc,CAAC,CAAC;AACnC,OAAO,CAAC,UAAU,CAAC,iBAAiB,CAAC,CAAC;AACtC,OAAO,CAAC,UAAU,CAAC,eAAe,CAAC,CAAC;AACpC,OAAO,CAAC,UAAU,CAAC,WAAW,CAAC,CAAC;AAChC,OAAO,CAAC,UAAU,CAAC,cAAc,CAAC,CAAC;AACnC,OAAO,CAAC,UAAU,CAAC,aAAa,CAAC,CAAC;AAClC,OAAO,CAAC,UAAU,CAAC,cAAc,CAAC,CAAC;AACnC,OAAO,CAAC,UAAU,CAAC,aAAa,CAAC,CAAC;AAClC,OAAO,CAAC,UAAU,CAAC,iBAAiB,CAAC,CAAC;AACtC,OAAO,CAAC,UAAU,CAAC,iBAAiB,CAAC,CAAC;AACtC,OAAO,CAAC,UAAU,CAAC,cAAc,CAAC,CAAC;AAEnC,OAAO,CAAC,UAAU,EAAE,CAAC,IAAI,CAAC,GAAG,EAAE,CAAC,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC,CAAC"}
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
import "dotenv/config";
|
|
2
|
+
import { Wallet, JsonRpcProvider } from "ethers";
|
|
3
|
+
/**
|
|
4
|
+
* Create an ethers Wallet signer from environment variables.
|
|
5
|
+
* Requires ENSHELL_PRIVATE_KEY and ENSHELL_RPC_URL in .env.
|
|
6
|
+
*/
|
|
7
|
+
export function envGetSigner() {
|
|
8
|
+
const rpcUrl = process.env.ENSHELL_RPC_URL;
|
|
9
|
+
if (!rpcUrl)
|
|
10
|
+
throw new Error("ENSHELL_RPC_URL not set in environment");
|
|
11
|
+
const pk = process.env.ENSHELL_PRIVATE_KEY;
|
|
12
|
+
if (!pk)
|
|
13
|
+
throw new Error("ENSHELL_PRIVATE_KEY not set in environment");
|
|
14
|
+
const provider = new JsonRpcProvider(rpcUrl);
|
|
15
|
+
return new Wallet(pk, provider);
|
|
16
|
+
}
|
|
17
|
+
//# sourceMappingURL=env.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"env.js","sourceRoot":"","sources":["../../src/wallets/env.ts"],"names":[],"mappings":"AAAA,OAAO,eAAe,CAAC;AACvB,OAAO,EAAE,MAAM,EAAE,eAAe,EAAE,MAAM,QAAQ,CAAC;AAEjD;;;GAGG;AACH,MAAM,UAAU,YAAY;IAC1B,MAAM,MAAM,GAAG,OAAO,CAAC,GAAG,CAAC,eAAe,CAAC;IAC3C,IAAI,CAAC,MAAM;QAAE,MAAM,IAAI,KAAK,CAAC,wCAAwC,CAAC,CAAC;IAEvE,MAAM,EAAE,GAAG,OAAO,CAAC,GAAG,CAAC,mBAAmB,CAAC;IAC3C,IAAI,CAAC,EAAE;QAAE,MAAM,IAAI,KAAK,CAAC,4CAA4C,CAAC,CAAC;IAEvE,MAAM,QAAQ,GAAG,IAAI,eAAe,CAAC,MAAM,CAAC,CAAC;IAC7C,OAAO,IAAI,MAAM,CAAC,EAAE,EAAE,QAAQ,CAAC,CAAC;AAClC,CAAC"}
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
import { Signer } from "ethers";
|
|
2
|
+
export type WalletMode = "walletconnect" | "env" | "ledger";
|
|
3
|
+
/**
|
|
4
|
+
* Resolve an ethers Signer based on the selected wallet mode.
|
|
5
|
+
*
|
|
6
|
+
* Default (no --wallet flag): WalletConnect (requires prior "enshell connect")
|
|
7
|
+
* --wallet env: Private key from .env
|
|
8
|
+
* --wallet ledger: Ledger USB (not yet implemented)
|
|
9
|
+
*/
|
|
10
|
+
export declare function resolveSigner(mode: WalletMode): Promise<Signer>;
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
import { envGetSigner } from "./env.js";
|
|
2
|
+
import { wcGetSigner } from "./walletconnect.js";
|
|
3
|
+
/**
|
|
4
|
+
* Resolve an ethers Signer based on the selected wallet mode.
|
|
5
|
+
*
|
|
6
|
+
* Default (no --wallet flag): WalletConnect (requires prior "enshell connect")
|
|
7
|
+
* --wallet env: Private key from .env
|
|
8
|
+
* --wallet ledger: Ledger USB (not yet implemented)
|
|
9
|
+
*/
|
|
10
|
+
export async function resolveSigner(mode) {
|
|
11
|
+
switch (mode) {
|
|
12
|
+
case "env":
|
|
13
|
+
return envGetSigner();
|
|
14
|
+
case "walletconnect":
|
|
15
|
+
return wcGetSigner();
|
|
16
|
+
case "ledger":
|
|
17
|
+
throw new Error("Ledger USB mode is not yet implemented. Use WalletConnect or --wallet env.");
|
|
18
|
+
default:
|
|
19
|
+
throw new Error(`Unknown wallet mode: ${mode}`);
|
|
20
|
+
}
|
|
21
|
+
}
|
|
22
|
+
//# sourceMappingURL=index.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/wallets/index.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,YAAY,EAAE,MAAM,UAAU,CAAC;AACxC,OAAO,EAAE,WAAW,EAAE,MAAM,oBAAoB,CAAC;AAIjD;;;;;;GAMG;AACH,MAAM,CAAC,KAAK,UAAU,aAAa,CAAC,IAAgB;IAClD,QAAQ,IAAI,EAAE,CAAC;QACb,KAAK,KAAK;YACR,OAAO,YAAY,EAAE,CAAC;QAExB,KAAK,eAAe;YAClB,OAAO,WAAW,EAAE,CAAC;QAEvB,KAAK,QAAQ;YACX,MAAM,IAAI,KAAK,CACb,4EAA4E,CAC7E,CAAC;QAEJ;YACE,MAAM,IAAI,KAAK,CAAC,wBAAwB,IAAI,EAAE,CAAC,CAAC;IACpD,CAAC;AACH,CAAC"}
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* File-based key-value storage for WalletConnect session persistence.
|
|
3
|
+
* Stores data in ~/.enshell/wc-session.json.
|
|
4
|
+
* Implements the KeyValueStorage interface expected by WalletConnect.
|
|
5
|
+
*/
|
|
6
|
+
export declare class FileStorage {
|
|
7
|
+
private data;
|
|
8
|
+
constructor();
|
|
9
|
+
private save;
|
|
10
|
+
getItem<T = unknown>(key: string): Promise<T | undefined>;
|
|
11
|
+
setItem<T = unknown>(key: string, value: T): Promise<void>;
|
|
12
|
+
removeItem(key: string): Promise<void>;
|
|
13
|
+
getKeys(): Promise<string[]>;
|
|
14
|
+
getEntries<T = unknown>(): Promise<Array<[string, T]>>;
|
|
15
|
+
/**
|
|
16
|
+
* Delete the entire session file.
|
|
17
|
+
*/
|
|
18
|
+
static clear(): void;
|
|
19
|
+
}
|
|
@@ -0,0 +1,62 @@
|
|
|
1
|
+
import { readFileSync, writeFileSync, mkdirSync, existsSync } from "fs";
|
|
2
|
+
import { join } from "path";
|
|
3
|
+
import { homedir } from "os";
|
|
4
|
+
const ENSHELL_DIR = join(homedir(), ".enshell");
|
|
5
|
+
const SESSION_FILE = join(ENSHELL_DIR, "wc-session.json");
|
|
6
|
+
function ensureDir() {
|
|
7
|
+
if (!existsSync(ENSHELL_DIR)) {
|
|
8
|
+
mkdirSync(ENSHELL_DIR, { recursive: true });
|
|
9
|
+
}
|
|
10
|
+
}
|
|
11
|
+
/**
|
|
12
|
+
* File-based key-value storage for WalletConnect session persistence.
|
|
13
|
+
* Stores data in ~/.enshell/wc-session.json.
|
|
14
|
+
* Implements the KeyValueStorage interface expected by WalletConnect.
|
|
15
|
+
*/
|
|
16
|
+
export class FileStorage {
|
|
17
|
+
data;
|
|
18
|
+
constructor() {
|
|
19
|
+
ensureDir();
|
|
20
|
+
if (existsSync(SESSION_FILE)) {
|
|
21
|
+
try {
|
|
22
|
+
this.data = JSON.parse(readFileSync(SESSION_FILE, "utf-8"));
|
|
23
|
+
}
|
|
24
|
+
catch {
|
|
25
|
+
this.data = {};
|
|
26
|
+
}
|
|
27
|
+
}
|
|
28
|
+
else {
|
|
29
|
+
this.data = {};
|
|
30
|
+
}
|
|
31
|
+
}
|
|
32
|
+
save() {
|
|
33
|
+
ensureDir();
|
|
34
|
+
writeFileSync(SESSION_FILE, JSON.stringify(this.data, null, 2));
|
|
35
|
+
}
|
|
36
|
+
async getItem(key) {
|
|
37
|
+
return this.data[key];
|
|
38
|
+
}
|
|
39
|
+
async setItem(key, value) {
|
|
40
|
+
this.data[key] = value;
|
|
41
|
+
this.save();
|
|
42
|
+
}
|
|
43
|
+
async removeItem(key) {
|
|
44
|
+
delete this.data[key];
|
|
45
|
+
this.save();
|
|
46
|
+
}
|
|
47
|
+
async getKeys() {
|
|
48
|
+
return Object.keys(this.data);
|
|
49
|
+
}
|
|
50
|
+
async getEntries() {
|
|
51
|
+
return Object.entries(this.data);
|
|
52
|
+
}
|
|
53
|
+
/**
|
|
54
|
+
* Delete the entire session file.
|
|
55
|
+
*/
|
|
56
|
+
static clear() {
|
|
57
|
+
if (existsSync(SESSION_FILE)) {
|
|
58
|
+
writeFileSync(SESSION_FILE, "{}");
|
|
59
|
+
}
|
|
60
|
+
}
|
|
61
|
+
}
|
|
62
|
+
//# sourceMappingURL=storage.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"storage.js","sourceRoot":"","sources":["../../src/wallets/storage.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,YAAY,EAAE,aAAa,EAAE,SAAS,EAAE,UAAU,EAAE,MAAM,IAAI,CAAC;AACxE,OAAO,EAAE,IAAI,EAAE,MAAM,MAAM,CAAC;AAC5B,OAAO,EAAE,OAAO,EAAE,MAAM,IAAI,CAAC;AAE7B,MAAM,WAAW,GAAG,IAAI,CAAC,OAAO,EAAE,EAAE,UAAU,CAAC,CAAC;AAChD,MAAM,YAAY,GAAG,IAAI,CAAC,WAAW,EAAE,iBAAiB,CAAC,CAAC;AAE1D,SAAS,SAAS;IAChB,IAAI,CAAC,UAAU,CAAC,WAAW,CAAC,EAAE,CAAC;QAC7B,SAAS,CAAC,WAAW,EAAE,EAAE,SAAS,EAAE,IAAI,EAAE,CAAC,CAAC;IAC9C,CAAC;AACH,CAAC;AAED;;;;GAIG;AACH,MAAM,OAAO,WAAW;IACd,IAAI,CAA0B;IAEtC;QACE,SAAS,EAAE,CAAC;QACZ,IAAI,UAAU,CAAC,YAAY,CAAC,EAAE,CAAC;YAC7B,IAAI,CAAC;gBACH,IAAI,CAAC,IAAI,GAAG,IAAI,CAAC,KAAK,CAAC,YAAY,CAAC,YAAY,EAAE,OAAO,CAAC,CAAC,CAAC;YAC9D,CAAC;YAAC,MAAM,CAAC;gBACP,IAAI,CAAC,IAAI,GAAG,EAAE,CAAC;YACjB,CAAC;QACH,CAAC;aAAM,CAAC;YACN,IAAI,CAAC,IAAI,GAAG,EAAE,CAAC;QACjB,CAAC;IACH,CAAC;IAEO,IAAI;QACV,SAAS,EAAE,CAAC;QACZ,aAAa,CAAC,YAAY,EAAE,IAAI,CAAC,SAAS,CAAC,IAAI,CAAC,IAAI,EAAE,IAAI,EAAE,CAAC,CAAC,CAAC,CAAC;IAClE,CAAC;IAED,KAAK,CAAC,OAAO,CAAc,GAAW;QACpC,OAAO,IAAI,CAAC,IAAI,CAAC,GAAG,CAAkB,CAAC;IACzC,CAAC;IAED,KAAK,CAAC,OAAO,CAAc,GAAW,EAAE,KAAQ;QAC9C,IAAI,CAAC,IAAI,CAAC,GAAG,CAAC,GAAG,KAAK,CAAC;QACvB,IAAI,CAAC,IAAI,EAAE,CAAC;IACd,CAAC;IAED,KAAK,CAAC,UAAU,CAAC,GAAW;QAC1B,OAAO,IAAI,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC;QACtB,IAAI,CAAC,IAAI,EAAE,CAAC;IACd,CAAC;IAED,KAAK,CAAC,OAAO;QACX,OAAO,MAAM,CAAC,IAAI,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;IAChC,CAAC;IAED,KAAK,CAAC,UAAU;QACd,OAAO,MAAM,CAAC,OAAO,CAAC,IAAI,CAAC,IAAI,CAAuB,CAAC;IACzD,CAAC;IAED;;OAEG;IACH,MAAM,CAAC,KAAK;QACV,IAAI,UAAU,CAAC,YAAY,CAAC,EAAE,CAAC;YAC7B,aAAa,CAAC,YAAY,EAAE,IAAI,CAAC,CAAC;QACpC,CAAC;IACH,CAAC;CACF"}
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
import { JsonRpcSigner } from "ethers";
|
|
2
|
+
/**
|
|
3
|
+
* Start a new WalletConnect session. Shows QR code in terminal.
|
|
4
|
+
* Saves session to ~/.enshell/wc-session.json for reuse.
|
|
5
|
+
* Returns the connected address.
|
|
6
|
+
*/
|
|
7
|
+
export declare function wcConnect(): Promise<string>;
|
|
8
|
+
/**
|
|
9
|
+
* Resume an existing WalletConnect session.
|
|
10
|
+
* Returns an ethers JsonRpcSigner if a valid session exists.
|
|
11
|
+
* Throws if no session is found.
|
|
12
|
+
*/
|
|
13
|
+
export declare function wcGetSigner(): Promise<JsonRpcSigner>;
|
|
14
|
+
/**
|
|
15
|
+
* Disconnect the WalletConnect session and clear stored session.
|
|
16
|
+
*/
|
|
17
|
+
export declare function wcDisconnect(): Promise<void>;
|
|
@@ -0,0 +1,94 @@
|
|
|
1
|
+
import { EthereumProvider } from "@walletconnect/ethereum-provider";
|
|
2
|
+
import { BrowserProvider } from "ethers";
|
|
3
|
+
import qrcode from "qrcode-terminal";
|
|
4
|
+
import chalk from "chalk";
|
|
5
|
+
import { FileStorage } from "./storage.js";
|
|
6
|
+
const PROJECT_ID = "7c42ddbb278eb49df82a8340fae31e95";
|
|
7
|
+
const SEPOLIA_CHAIN_ID = 11155111;
|
|
8
|
+
async function initProvider() {
|
|
9
|
+
const storage = new FileStorage();
|
|
10
|
+
const provider = await EthereumProvider.init({
|
|
11
|
+
projectId: PROJECT_ID,
|
|
12
|
+
metadata: {
|
|
13
|
+
name: "ENShell CLI",
|
|
14
|
+
description: "On-chain firewall for AI agents",
|
|
15
|
+
url: "https://enshell.xyz",
|
|
16
|
+
icons: ["https://enshell.xyz/assets/images/enshell-icon.png"],
|
|
17
|
+
},
|
|
18
|
+
showQrModal: false,
|
|
19
|
+
optionalChains: [SEPOLIA_CHAIN_ID],
|
|
20
|
+
optionalMethods: [
|
|
21
|
+
"eth_sendTransaction",
|
|
22
|
+
"personal_sign",
|
|
23
|
+
"eth_signTypedData_v4",
|
|
24
|
+
"eth_accounts",
|
|
25
|
+
"eth_requestAccounts",
|
|
26
|
+
"eth_call",
|
|
27
|
+
"eth_getBalance",
|
|
28
|
+
"eth_signTransaction",
|
|
29
|
+
],
|
|
30
|
+
optionalEvents: ["chainChanged", "accountsChanged"],
|
|
31
|
+
storage,
|
|
32
|
+
rpcMap: {
|
|
33
|
+
[SEPOLIA_CHAIN_ID]: process.env.ENSHELL_RPC_URL || "https://rpc.sepolia.org",
|
|
34
|
+
},
|
|
35
|
+
});
|
|
36
|
+
return provider;
|
|
37
|
+
}
|
|
38
|
+
/**
|
|
39
|
+
* Start a new WalletConnect session. Shows QR code in terminal.
|
|
40
|
+
* Saves session to ~/.enshell/wc-session.json for reuse.
|
|
41
|
+
* Returns the connected address.
|
|
42
|
+
*/
|
|
43
|
+
export async function wcConnect() {
|
|
44
|
+
const provider = await initProvider();
|
|
45
|
+
// Check if there's already an active session
|
|
46
|
+
if (provider.session) {
|
|
47
|
+
const address = provider.accounts[0];
|
|
48
|
+
if (address) {
|
|
49
|
+
return address;
|
|
50
|
+
}
|
|
51
|
+
}
|
|
52
|
+
// No existing session — show QR code
|
|
53
|
+
return new Promise((resolve, reject) => {
|
|
54
|
+
provider.on("display_uri", (uri) => {
|
|
55
|
+
console.log(chalk.cyan("\n Scan this QR code with your wallet (MetaMask, Rainbow, etc.)\n"));
|
|
56
|
+
qrcode.generate(uri, { small: true });
|
|
57
|
+
console.log(chalk.gray("\n Or paste this URI in your wallet:"));
|
|
58
|
+
console.log(chalk.gray(` ${uri}\n`));
|
|
59
|
+
console.log(chalk.gray(" Waiting for approval..."));
|
|
60
|
+
});
|
|
61
|
+
provider
|
|
62
|
+
.connect()
|
|
63
|
+
.then(() => {
|
|
64
|
+
const address = provider.accounts[0];
|
|
65
|
+
resolve(address);
|
|
66
|
+
})
|
|
67
|
+
.catch(reject);
|
|
68
|
+
});
|
|
69
|
+
}
|
|
70
|
+
/**
|
|
71
|
+
* Resume an existing WalletConnect session.
|
|
72
|
+
* Returns an ethers JsonRpcSigner if a valid session exists.
|
|
73
|
+
* Throws if no session is found.
|
|
74
|
+
*/
|
|
75
|
+
export async function wcGetSigner() {
|
|
76
|
+
const provider = await initProvider();
|
|
77
|
+
if (!provider.session || !provider.accounts[0]) {
|
|
78
|
+
throw new Error('No wallet connected. Run "enshell connect" first.\n' +
|
|
79
|
+
" Alternatively, use --wallet env (.env private key).");
|
|
80
|
+
}
|
|
81
|
+
const ethersProvider = new BrowserProvider(provider);
|
|
82
|
+
return ethersProvider.getSigner();
|
|
83
|
+
}
|
|
84
|
+
/**
|
|
85
|
+
* Disconnect the WalletConnect session and clear stored session.
|
|
86
|
+
*/
|
|
87
|
+
export async function wcDisconnect() {
|
|
88
|
+
const provider = await initProvider();
|
|
89
|
+
if (provider.session) {
|
|
90
|
+
await provider.disconnect();
|
|
91
|
+
}
|
|
92
|
+
FileStorage.clear();
|
|
93
|
+
}
|
|
94
|
+
//# sourceMappingURL=walletconnect.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"walletconnect.js","sourceRoot":"","sources":["../../src/wallets/walletconnect.ts"],"names":[],"mappings":"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"}
|
package/package.json
ADDED
|
@@ -0,0 +1,38 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "@enshell/cli",
|
|
3
|
+
"version": "0.1.0-beta.1",
|
|
4
|
+
"type": "module",
|
|
5
|
+
"bin": {
|
|
6
|
+
"enshell": "dist/index.js"
|
|
7
|
+
},
|
|
8
|
+
"files": [
|
|
9
|
+
"dist"
|
|
10
|
+
],
|
|
11
|
+
"scripts": {
|
|
12
|
+
"build": "tsc",
|
|
13
|
+
"dev": "node --loader ts-node/esm src/index.ts",
|
|
14
|
+
"test": "vitest run",
|
|
15
|
+
"test:coverage": "vitest run --coverage",
|
|
16
|
+
"clean": "rm -rf dist",
|
|
17
|
+
"prepublishOnly": "npm run build"
|
|
18
|
+
},
|
|
19
|
+
"dependencies": {
|
|
20
|
+
"@enshell/sdk": "^0.1.0-beta.9",
|
|
21
|
+
"@walletconnect/ethereum-provider": "^2.23.9",
|
|
22
|
+
"chalk": "^5.4.1",
|
|
23
|
+
"commander": "^14.0.0",
|
|
24
|
+
"dotenv": "^16.5.0",
|
|
25
|
+
"ethers": "^6.15.0",
|
|
26
|
+
"ora": "^8.2.0",
|
|
27
|
+
"qrcode-terminal": "^0.12.0"
|
|
28
|
+
},
|
|
29
|
+
"devDependencies": {
|
|
30
|
+
"@types/node": "^22.18.11",
|
|
31
|
+
"@vitest/coverage-v8": "^4.1.2",
|
|
32
|
+
"typescript": "~5.8.0",
|
|
33
|
+
"vitest": "^4.1.2"
|
|
34
|
+
},
|
|
35
|
+
"publishConfig": {
|
|
36
|
+
"access": "public"
|
|
37
|
+
}
|
|
38
|
+
}
|