arc402-cli 0.3.4 → 0.4.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/dist/commands/accept.d.ts.map +1 -1
- package/dist/commands/accept.js +17 -7
- package/dist/commands/accept.js.map +1 -1
- package/dist/commands/agent-handshake.d.ts.map +1 -1
- package/dist/commands/agent-handshake.js +9 -4
- package/dist/commands/agent-handshake.js.map +1 -1
- package/dist/commands/agent.d.ts.map +1 -1
- package/dist/commands/agent.js +14 -8
- package/dist/commands/agent.js.map +1 -1
- package/dist/commands/agreements.d.ts.map +1 -1
- package/dist/commands/agreements.js +51 -26
- package/dist/commands/agreements.js.map +1 -1
- package/dist/commands/arbitrator.d.ts.map +1 -1
- package/dist/commands/arbitrator.js +15 -7
- package/dist/commands/arbitrator.js.map +1 -1
- package/dist/commands/arena-handshake.d.ts.map +1 -1
- package/dist/commands/arena-handshake.js +14 -11
- package/dist/commands/arena-handshake.js.map +1 -1
- package/dist/commands/channel.d.ts.map +1 -1
- package/dist/commands/channel.js +27 -17
- package/dist/commands/channel.js.map +1 -1
- package/dist/commands/coldstart.d.ts.map +1 -1
- package/dist/commands/coldstart.js +33 -22
- package/dist/commands/coldstart.js.map +1 -1
- package/dist/commands/config.d.ts.map +1 -1
- package/dist/commands/config.js +33 -17
- package/dist/commands/config.js.map +1 -1
- package/dist/commands/daemon.d.ts.map +1 -1
- package/dist/commands/daemon.js +44 -37
- package/dist/commands/daemon.js.map +1 -1
- package/dist/commands/endpoint.d.ts.map +1 -1
- package/dist/commands/endpoint.js +4 -3
- package/dist/commands/endpoint.js.map +1 -1
- package/dist/commands/feed.d.ts.map +1 -1
- package/dist/commands/feed.js.map +1 -1
- package/dist/commands/hire.d.ts.map +1 -1
- package/dist/commands/hire.js +3 -0
- package/dist/commands/hire.js.map +1 -1
- package/dist/commands/owner.d.ts.map +1 -1
- package/dist/commands/owner.js +5 -1
- package/dist/commands/owner.js.map +1 -1
- package/dist/commands/policy.d.ts.map +1 -1
- package/dist/commands/policy.js.map +1 -1
- package/dist/commands/relay.d.ts.map +1 -1
- package/dist/commands/relay.js.map +1 -1
- package/dist/commands/remediate.d.ts.map +1 -1
- package/dist/commands/remediate.js.map +1 -1
- package/dist/commands/reputation.d.ts.map +1 -1
- package/dist/commands/reputation.js.map +1 -1
- package/dist/commands/trust.d.ts.map +1 -1
- package/dist/commands/trust.js.map +1 -1
- package/dist/commands/verify.d.ts.map +1 -1
- package/dist/commands/verify.js.map +1 -1
- package/dist/commands/wallet.d.ts.map +1 -1
- package/dist/commands/wallet.js +15 -5
- package/dist/commands/wallet.js.map +1 -1
- package/dist/commands/watch.d.ts +3 -0
- package/dist/commands/watch.d.ts.map +1 -0
- package/dist/commands/watch.js +23 -0
- package/dist/commands/watch.js.map +1 -0
- package/dist/commands/watchtower.d.ts.map +1 -1
- package/dist/commands/watchtower.js.map +1 -1
- package/dist/config.d.ts.map +1 -1
- package/dist/config.js +15 -2
- package/dist/config.js.map +1 -1
- package/dist/index.js +73 -38
- package/dist/index.js.map +1 -1
- package/dist/ui/banner.d.ts.map +1 -1
- package/dist/ui/banner.js +4 -2
- package/dist/ui/banner.js.map +1 -1
- package/dist/ui/tree.d.ts +7 -0
- package/dist/ui/tree.d.ts.map +1 -0
- package/dist/ui/tree.js +13 -0
- package/dist/ui/tree.js.map +1 -0
- package/package.json +1 -1
- package/src/commands/accept.ts +19 -10
- package/src/commands/agent-handshake.ts +9 -4
- package/src/commands/agent.ts +15 -6
- package/src/commands/agreements.ts +51 -25
- package/src/commands/arbitrator.ts +26 -10
- package/src/commands/arena-handshake.ts +15 -8
- package/src/commands/channel.ts +27 -17
- package/src/commands/coldstart.ts +29 -20
- package/src/commands/config.ts +33 -17
- package/src/commands/daemon.ts +45 -38
- package/src/commands/endpoint.ts +4 -3
- package/src/commands/feed.ts +1 -0
- package/src/commands/hire.ts +8 -0
- package/src/commands/owner.ts +5 -1
- package/src/commands/policy.ts +3 -0
- package/src/commands/relay.ts +1 -0
- package/src/commands/remediate.ts +2 -0
- package/src/commands/reputation.ts +4 -0
- package/src/commands/trust.ts +3 -0
- package/src/commands/verify.ts +2 -0
- package/src/commands/wallet.ts +15 -5
- package/src/commands/watch.ts +23 -0
- package/src/commands/watchtower.ts +4 -0
- package/src/config.ts +15 -2
- package/src/index.ts +43 -3
- package/src/ui/banner.ts +5 -2
- package/src/ui/tree.ts +16 -0
|
@@ -3,6 +3,9 @@ import { ethers } from "ethers";
|
|
|
3
3
|
import { loadConfig, getUsdcAddress } from "../config";
|
|
4
4
|
import { requireSigner } from "../client";
|
|
5
5
|
import { AGENT_REGISTRY_ABI } from "../abis";
|
|
6
|
+
import { startSpinner } from "../ui/spinner";
|
|
7
|
+
import { renderTree } from "../ui/tree";
|
|
8
|
+
import { c } from "../ui/colors";
|
|
6
9
|
|
|
7
10
|
const DEFAULT_REGISTRY_ADDRESS = "0xD5c2851B00090c92Ba7F4723FB548bb30C9B6865";
|
|
8
11
|
|
|
@@ -122,6 +125,7 @@ export function registerArenaHandshakeCommands(program: Command): void {
|
|
|
122
125
|
|
|
123
126
|
const handshake = new ethers.Contract(config.handshakeAddress, HANDSHAKE_ABI, signer);
|
|
124
127
|
|
|
128
|
+
const hsSpinner = startSpinner(`Sending ${opts.type} handshake...`);
|
|
125
129
|
let tx;
|
|
126
130
|
if (opts.usdc) {
|
|
127
131
|
// USDC handshake
|
|
@@ -133,6 +137,7 @@ export function registerArenaHandshakeCommands(program: Command): void {
|
|
|
133
137
|
const value = opts.tip ? ethers.parseEther(opts.tip) : 0n;
|
|
134
138
|
tx = await handshake.sendHandshake(agentAddress, hsType, opts.note, { value });
|
|
135
139
|
}
|
|
140
|
+
hsSpinner.succeed("Handshake sent");
|
|
136
141
|
|
|
137
142
|
// Notify recipient's HTTP endpoint (non-blocking)
|
|
138
143
|
const registryAddress = config.agentRegistryV2Address ?? config.agentRegistryAddress ?? DEFAULT_REGISTRY_ADDRESS;
|
|
@@ -150,14 +155,16 @@ export function registerArenaHandshakeCommands(program: Command): void {
|
|
|
150
155
|
if (opts.json) {
|
|
151
156
|
console.log(JSON.stringify({ tx: tx.hash, from: myAddress, to: agentAddress, type: opts.type, note: opts.note }));
|
|
152
157
|
} else {
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
158
|
+
const treeItems = [
|
|
159
|
+
{ label: "From", value: myAddress },
|
|
160
|
+
{ label: "To", value: agentAddress },
|
|
161
|
+
{ label: "Type", value: opts.type },
|
|
162
|
+
...(opts.note ? [{ label: "Note", value: opts.note as string }] : []),
|
|
163
|
+
...(opts.tip ? [{ label: "Tip", value: `${opts.tip as string} ETH` }] : []),
|
|
164
|
+
...(opts.usdc ? [{ label: "Tip", value: `${opts.usdc as string} USDC` }] : []),
|
|
165
|
+
{ label: "Tx", value: tx.hash as string, last: true },
|
|
166
|
+
];
|
|
167
|
+
renderTree(treeItems);
|
|
161
168
|
}
|
|
162
169
|
});
|
|
163
170
|
|
package/src/commands/channel.ts
CHANGED
|
@@ -6,6 +6,10 @@ import type { ChannelState } from "@arc402/sdk";
|
|
|
6
6
|
import * as fs from "fs";
|
|
7
7
|
import * as path from "path";
|
|
8
8
|
import * as os from "os";
|
|
9
|
+
import { c } from '../ui/colors';
|
|
10
|
+
import { startSpinner } from '../ui/spinner';
|
|
11
|
+
import { renderTree } from '../ui/tree';
|
|
12
|
+
import { formatAddress } from '../ui/format';
|
|
9
13
|
|
|
10
14
|
const CHANNEL_STATES_DIR = path.join(os.homedir(), ".arc402", "channel-states");
|
|
11
15
|
|
|
@@ -33,6 +37,7 @@ export function registerChannelCommands(program: Command): void {
|
|
|
33
37
|
if (!config.serviceAgreementAddress) throw new Error("serviceAgreementAddress missing in config");
|
|
34
38
|
const { signer } = await requireSigner(config);
|
|
35
39
|
const client = new ChannelClient(config.serviceAgreementAddress, signer);
|
|
40
|
+
const spinner = startSpinner('Opening session channel…');
|
|
36
41
|
const result = await client.openSessionChannel(
|
|
37
42
|
provider,
|
|
38
43
|
opts.token,
|
|
@@ -41,10 +46,14 @@ export function registerChannelCommands(program: Command): void {
|
|
|
41
46
|
Number(opts.deadline)
|
|
42
47
|
);
|
|
43
48
|
if (opts.json || program.opts().json) {
|
|
49
|
+
spinner.stop();
|
|
44
50
|
console.log(JSON.stringify(result, null, 2));
|
|
45
51
|
} else {
|
|
46
|
-
|
|
47
|
-
|
|
52
|
+
spinner.succeed(' Opened — channel ' + result.channelId);
|
|
53
|
+
renderTree([
|
|
54
|
+
{ label: 'Channel', value: result.channelId },
|
|
55
|
+
{ label: 'Tx', value: result.txHash, last: true },
|
|
56
|
+
]);
|
|
48
57
|
}
|
|
49
58
|
});
|
|
50
59
|
|
|
@@ -60,14 +69,15 @@ export function registerChannelCommands(program: Command): void {
|
|
|
60
69
|
if (opts.json || program.opts().json) {
|
|
61
70
|
console.log(JSON.stringify(ch, (_k, v) => typeof v === "bigint" ? v.toString() : v, 2));
|
|
62
71
|
} else {
|
|
63
|
-
console.log(`
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
72
|
+
console.log('\n ' + c.mark + c.white(` Channel ${channelId}`));
|
|
73
|
+
renderTree([
|
|
74
|
+
{ label: 'Status', value: ch.status },
|
|
75
|
+
{ label: 'Client', value: formatAddress(ch.client) },
|
|
76
|
+
{ label: 'Provider', value: formatAddress(ch.provider) },
|
|
77
|
+
{ label: 'Deposit', value: ch.depositAmount.toString() },
|
|
78
|
+
{ label: 'Settled', value: ch.settledAmount.toString() },
|
|
79
|
+
{ label: 'Seq', value: ch.lastSequenceNumber.toString(), last: true },
|
|
80
|
+
]);
|
|
71
81
|
}
|
|
72
82
|
});
|
|
73
83
|
|
|
@@ -107,8 +117,8 @@ export function registerChannelCommands(program: Command): void {
|
|
|
107
117
|
if (opts.json || program.opts().json) {
|
|
108
118
|
console.log(JSON.stringify(result, null, 2));
|
|
109
119
|
} else {
|
|
110
|
-
console.log(`
|
|
111
|
-
console.log(
|
|
120
|
+
console.log(' ' + c.success + c.white(` Close submitted — ${result.txHash}`));
|
|
121
|
+
console.log(' ' + c.dim('Challenge window open (24h)'));
|
|
112
122
|
}
|
|
113
123
|
});
|
|
114
124
|
|
|
@@ -126,7 +136,7 @@ export function registerChannelCommands(program: Command): void {
|
|
|
126
136
|
if (opts.json || program.opts().json) {
|
|
127
137
|
console.log(JSON.stringify(result, null, 2));
|
|
128
138
|
} else {
|
|
129
|
-
console.log(`
|
|
139
|
+
console.log(' ' + c.success + c.white(` Challenge submitted — ${result.txHash}`));
|
|
130
140
|
}
|
|
131
141
|
});
|
|
132
142
|
|
|
@@ -142,7 +152,7 @@ export function registerChannelCommands(program: Command): void {
|
|
|
142
152
|
if (opts.json || program.opts().json) {
|
|
143
153
|
console.log(JSON.stringify(result, null, 2));
|
|
144
154
|
} else {
|
|
145
|
-
console.log(`
|
|
155
|
+
console.log(' ' + c.success + c.white(` Finalised — ${result.txHash}`));
|
|
146
156
|
}
|
|
147
157
|
});
|
|
148
158
|
|
|
@@ -158,7 +168,7 @@ export function registerChannelCommands(program: Command): void {
|
|
|
158
168
|
if (opts.json || program.opts().json) {
|
|
159
169
|
console.log(JSON.stringify(result, null, 2));
|
|
160
170
|
} else {
|
|
161
|
-
console.log(`
|
|
171
|
+
console.log(' ' + c.success + c.white(` Reclaimed — ${result.txHash}`));
|
|
162
172
|
}
|
|
163
173
|
});
|
|
164
174
|
|
|
@@ -201,8 +211,8 @@ export function registerChannelCommands(program: Command): void {
|
|
|
201
211
|
if (opts.json || program.opts().json) {
|
|
202
212
|
console.log(JSON.stringify({ stored: true, channelId, path: dest }));
|
|
203
213
|
} else {
|
|
204
|
-
console.log(`State stored
|
|
205
|
-
console.log(`
|
|
214
|
+
console.log(' ' + c.success + c.white(` State stored — ${dest}`));
|
|
215
|
+
console.log(' ' + c.dim(`seq: ${state.sequenceNumber}`));
|
|
206
216
|
}
|
|
207
217
|
});
|
|
208
218
|
}
|
|
@@ -2,6 +2,9 @@ import { Command } from "commander";
|
|
|
2
2
|
import { ethers } from "ethers";
|
|
3
3
|
import { loadConfig } from "../config";
|
|
4
4
|
import { getClient, requireSigner } from "../client";
|
|
5
|
+
import { c } from '../ui/colors';
|
|
6
|
+
import { startSpinner } from '../ui/spinner';
|
|
7
|
+
import { renderTree } from '../ui/tree';
|
|
5
8
|
|
|
6
9
|
const VOUCHING_REGISTRY_ABI = [
|
|
7
10
|
"function vouch(address newAgent, uint256 stakeAmount) external payable",
|
|
@@ -42,6 +45,7 @@ export function registerColdStartCommands(program: Command): void {
|
|
|
42
45
|
const stakeAmount = opts.stake ? BigInt(opts.stake) : 0n;
|
|
43
46
|
const contract = new ethers.Contract(config.vouchingRegistryAddress, VOUCHING_REGISTRY_ABI, signer);
|
|
44
47
|
|
|
48
|
+
const spinner = startSpinner(`Vouching for ${address}…`);
|
|
45
49
|
const tx = await contract.vouch(address, stakeAmount);
|
|
46
50
|
const receipt = await tx.wait();
|
|
47
51
|
|
|
@@ -53,11 +57,14 @@ export function registerColdStartCommands(program: Command): void {
|
|
|
53
57
|
boostGranted: boost.toString(),
|
|
54
58
|
txHash: receipt.hash,
|
|
55
59
|
};
|
|
56
|
-
if (opts.json) return console.log(JSON.stringify(payload, null, 2));
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
60
|
+
if (opts.json) { spinner.stop(); return console.log(JSON.stringify(payload, null, 2)); }
|
|
61
|
+
spinner.succeed(` Vouched — ${address}`);
|
|
62
|
+
renderTree([
|
|
63
|
+
{ label: 'New Agent', value: address },
|
|
64
|
+
{ label: 'Stake', value: stakeAmount > 0n ? `${ethers.formatEther(stakeAmount)} ETH` : '0' },
|
|
65
|
+
{ label: 'Boost', value: `+${boost} trust points` },
|
|
66
|
+
{ label: 'Tx', value: receipt.hash, last: true },
|
|
67
|
+
]);
|
|
61
68
|
});
|
|
62
69
|
|
|
63
70
|
// ─── bond ──────────────────────────────────────────────────────────────────
|
|
@@ -88,14 +95,18 @@ export function registerColdStartCommands(program: Command): void {
|
|
|
88
95
|
}
|
|
89
96
|
|
|
90
97
|
const amount = opts.amount ? BigInt(opts.amount) : BOND_DEFAULT_AMOUNT;
|
|
98
|
+
const bondSpinner = startSpinner('Posting bond…');
|
|
91
99
|
const tx = await contract.postBond({ value: amount });
|
|
92
100
|
const receipt = await tx.wait();
|
|
93
101
|
|
|
94
102
|
const payload = { bonded: true, amount: amount.toString(), txHash: receipt.hash };
|
|
95
|
-
if (opts.json) return console.log(JSON.stringify(payload, null, 2));
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
103
|
+
if (opts.json) { bondSpinner.stop(); return console.log(JSON.stringify(payload, null, 2)); }
|
|
104
|
+
bondSpinner.succeed(` Bond posted — ${ethers.formatEther(amount)} ETH`);
|
|
105
|
+
renderTree([
|
|
106
|
+
{ label: 'Amount', value: `${ethers.formatEther(amount)} ETH` },
|
|
107
|
+
{ label: 'Tx', value: receipt.hash },
|
|
108
|
+
{ label: 'Note', value: 'Claimable after 90 days of clean operation', last: true },
|
|
109
|
+
]);
|
|
99
110
|
});
|
|
100
111
|
|
|
101
112
|
// arc402 bond status <address>
|
|
@@ -121,8 +132,8 @@ export function registerColdStartCommands(program: Command): void {
|
|
|
121
132
|
} catch {
|
|
122
133
|
const payload = { address, bonded: false };
|
|
123
134
|
if (opts.json) return console.log(JSON.stringify(payload, null, 2));
|
|
124
|
-
console.log(`
|
|
125
|
-
|
|
135
|
+
console.log('\n ' + c.mark + c.white(` Bond Status — ${address}`));
|
|
136
|
+
renderTree([{ label: 'Status', value: 'No active bond', last: true }]);
|
|
126
137
|
return;
|
|
127
138
|
}
|
|
128
139
|
|
|
@@ -140,17 +151,15 @@ export function registerColdStartCommands(program: Command): void {
|
|
|
140
151
|
daysRemaining,
|
|
141
152
|
};
|
|
142
153
|
if (opts.json) return console.log(JSON.stringify(payload, null, 2));
|
|
143
|
-
console.log(`
|
|
154
|
+
console.log('\n ' + c.mark + c.white(` Bond Status — ${address}`));
|
|
144
155
|
if (!active) {
|
|
145
|
-
|
|
156
|
+
renderTree([{ label: 'Status', value: 'No active bond', last: true }]);
|
|
146
157
|
return;
|
|
147
158
|
}
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
console.log(` claimable: now`);
|
|
154
|
-
}
|
|
159
|
+
renderTree([
|
|
160
|
+
{ label: 'Amount', value: `${ethers.formatEther(amount)} ETH` },
|
|
161
|
+
{ label: 'Posted', value: new Date(Number(postedAt) * 1000).toISOString() },
|
|
162
|
+
{ label: 'Claimable', value: daysRemaining > 0 ? `in ${daysRemaining} days` : 'now', last: true },
|
|
163
|
+
]);
|
|
155
164
|
});
|
|
156
165
|
}
|
package/src/commands/config.ts
CHANGED
|
@@ -2,31 +2,47 @@ import { Command } from "commander";
|
|
|
2
2
|
import prompts from "prompts";
|
|
3
3
|
import chalk from "chalk";
|
|
4
4
|
import { Arc402Config, NETWORK_DEFAULTS, configExists, loadConfig, saveConfig, getSubdomainApi } from "../config";
|
|
5
|
+
import { c } from '../ui/colors';
|
|
5
6
|
|
|
6
7
|
export function registerConfigCommands(program: Command): void {
|
|
7
8
|
const config = program.command("config").description("Manage ARC-402 CLI configuration");
|
|
8
9
|
config.command("init").description("Interactive setup for ~/.arc402/config.json").action(async () => {
|
|
9
10
|
const existing: Partial<Arc402Config> = configExists() ? loadConfig() : {};
|
|
10
11
|
const answers = await prompts([
|
|
11
|
-
{ type: "select", name: "network", message: "Network", choices: [{ title: "Base
|
|
12
|
-
{ type: "text", name: "rpcUrl", message: "RPC URL", initial: (_: unknown, values: Record<string, string>) => existing.rpcUrl ?? NETWORK_DEFAULTS[values.network]?.rpcUrl ?? "" },
|
|
13
|
-
{ type: "text", name: "agentRegistryAddress", message: "AgentRegistry address (optional)", initial: existing.agentRegistryAddress ?? "" },
|
|
14
|
-
{ type: "text", name: "serviceAgreementAddress", message: "ServiceAgreement address (optional)", initial: existing.serviceAgreementAddress ?? "" },
|
|
15
|
-
{ type: "text", name: "trustRegistryAddress", message: "TrustRegistry / TrustRegistryV3 address", initial: (_: unknown, values: Record<string, string>) => existing.trustRegistryAddress ?? NETWORK_DEFAULTS[values.network]?.trustRegistryAddress ?? "" },
|
|
16
|
-
{ type: "text", name: "reputationOracleAddress", message: "ReputationOracle address (optional)", initial: existing.reputationOracleAddress ?? "" },
|
|
17
|
-
{ type: "text", name: "sponsorshipAttestationAddress", message: "SponsorshipAttestation address (optional)", initial: existing.sponsorshipAttestationAddress ?? "" },
|
|
18
|
-
{ type: "text", name: "capabilityRegistryAddress", message: "CapabilityRegistry address (optional)", initial: existing.capabilityRegistryAddress ?? "" },
|
|
19
|
-
{ type: "text", name: "governanceAddress", message: "ARC402Governance address (optional)", initial: existing.governanceAddress ?? "" },
|
|
20
|
-
{ type: "confirm", name: "storeKey", message: "Store private key in config?", initial: false },
|
|
21
|
-
{ type: (prev: boolean) => prev ? "password" : null, name: "privateKey", message: "Private key (0x...)" },
|
|
22
|
-
{ type: "text", name: "subdomainApi", message: "Subdomain API endpoint (optional, default: https://api.arc402.xyz):", initial: existing.subdomainApi ?? "" },
|
|
23
|
-
{ type: "text", name: "telegramBotToken", message: "Telegram bot token (optional, for approval notifications):", initial: existing.telegramBotToken ?? "" },
|
|
24
|
-
{ type: "text", name: "telegramChatId", message: "Telegram chat ID (optional):", initial: existing.telegramChatId ?? "" },
|
|
25
|
-
{ type: "text", name: "telegramThreadId", message: "Telegram thread ID (optional, for forum topics):", initial: existing.telegramThreadId?.toString() ?? "" },
|
|
12
|
+
{ type: "select", name: "network", message: "Network", choices: [{ title: "Base Mainnet", value: "base-mainnet" }, { title: "Base Sepolia (testnet)", value: "base-sepolia" }], initial: existing.network === "base-sepolia" ? 1 : 0 },
|
|
26
13
|
]);
|
|
27
|
-
|
|
14
|
+
|
|
15
|
+
if (!answers.network) { console.log(chalk.red("✗ Setup cancelled")); return; }
|
|
16
|
+
|
|
17
|
+
const defaults = NETWORK_DEFAULTS[answers.network] ?? {};
|
|
18
|
+
const cfg: Arc402Config = {
|
|
19
|
+
network: answers.network,
|
|
20
|
+
rpcUrl: defaults.rpcUrl ?? "https://mainnet.base.org",
|
|
21
|
+
trustRegistryAddress: defaults.trustRegistryAddress ?? "",
|
|
22
|
+
agentRegistryAddress: defaults.agentRegistryV2Address ?? defaults.agentRegistryAddress,
|
|
23
|
+
serviceAgreementAddress: defaults.serviceAgreementAddress,
|
|
24
|
+
reputationOracleAddress: defaults.reputationOracleAddress,
|
|
25
|
+
sponsorshipAttestationAddress: defaults.sponsorshipAttestationAddress,
|
|
26
|
+
capabilityRegistryAddress: defaults.capabilityRegistryAddress,
|
|
27
|
+
governanceAddress: defaults.governanceAddress,
|
|
28
|
+
...(existing.privateKey ? { privateKey: existing.privateKey } : {}),
|
|
29
|
+
...(existing.subdomainApi ? { subdomainApi: existing.subdomainApi } : {}),
|
|
30
|
+
...(existing.telegramBotToken ? { telegramBotToken: existing.telegramBotToken } : {}),
|
|
31
|
+
...(existing.telegramChatId ? { telegramChatId: existing.telegramChatId } : {}),
|
|
32
|
+
...(existing.telegramThreadId ? { telegramThreadId: existing.telegramThreadId } : {}),
|
|
33
|
+
...(existing.walletContractAddress ? { walletContractAddress: existing.walletContractAddress } : {}),
|
|
34
|
+
};
|
|
28
35
|
saveConfig(cfg);
|
|
29
|
-
|
|
36
|
+
|
|
37
|
+
console.log();
|
|
38
|
+
console.log(' ' + c.success + c.white(' Config saved'));
|
|
39
|
+
console.log();
|
|
40
|
+
console.log(chalk.dim(" Network ") + chalk.white(answers.network === "base-mainnet" ? "Base Mainnet" : "Base Sepolia"));
|
|
41
|
+
console.log(chalk.dim(" RPC ") + chalk.white(cfg.rpcUrl!));
|
|
42
|
+
console.log(chalk.dim(" Contracts ") + chalk.white("All protocol addresses loaded"));
|
|
43
|
+
console.log();
|
|
44
|
+
console.log(chalk.dim(" Next: ") + chalk.white("arc402 wallet deploy"));
|
|
45
|
+
console.log();
|
|
30
46
|
});
|
|
31
47
|
config.command("show").description("Print current config").action(() => {
|
|
32
48
|
const cfg = loadConfig();
|
package/src/commands/daemon.ts
CHANGED
|
@@ -8,6 +8,9 @@ import { ethers } from "ethers";
|
|
|
8
8
|
import prompts from "prompts";
|
|
9
9
|
import { loadConfig } from "../config";
|
|
10
10
|
import { requireSigner } from "../client";
|
|
11
|
+
import { startSpinner } from "../ui/spinner";
|
|
12
|
+
import { renderTree } from "../ui/tree";
|
|
13
|
+
import { c } from "../ui/colors";
|
|
11
14
|
import { SERVICE_AGREEMENT_ABI } from "../abis";
|
|
12
15
|
import {
|
|
13
16
|
DAEMON_DIR,
|
|
@@ -344,15 +347,21 @@ async function startDaemonBackground(sandboxName?: string, runtimeRemoteRoot?: s
|
|
|
344
347
|
if (sandboxName) {
|
|
345
348
|
const remotePid = await readRemotePid(sandboxName);
|
|
346
349
|
if (remotePid) {
|
|
347
|
-
console.log(`ARC-402 daemon started
|
|
348
|
-
|
|
350
|
+
console.log(` ${c.success} ARC-402 daemon started (OpenShell)`);
|
|
351
|
+
renderTree([
|
|
352
|
+
{ label: "PID", value: String(remotePid) },
|
|
353
|
+
{ label: "Log", value: REMOTE_DAEMON_LOG, last: true },
|
|
354
|
+
]);
|
|
349
355
|
return;
|
|
350
356
|
}
|
|
351
357
|
} else {
|
|
352
358
|
const pid = readPid();
|
|
353
359
|
if (pid && isProcessAlive(pid)) {
|
|
354
|
-
console.log(`ARC-402 daemon started
|
|
355
|
-
|
|
360
|
+
console.log(` ${c.success} ARC-402 daemon started`);
|
|
361
|
+
renderTree([
|
|
362
|
+
{ label: "PID", value: String(pid) },
|
|
363
|
+
{ label: "Log", value: DAEMON_LOG, last: true },
|
|
364
|
+
]);
|
|
356
365
|
return;
|
|
357
366
|
}
|
|
358
367
|
}
|
|
@@ -408,34 +417,31 @@ async function stopDaemon(opts: { wait?: boolean } = {}): Promise<boolean> {
|
|
|
408
417
|
// ─── Output formatters ────────────────────────────────────────────────────────
|
|
409
418
|
|
|
410
419
|
function formatStatus(data: Record<string, unknown>): void {
|
|
411
|
-
const line = (label: string, value: string) =>
|
|
412
|
-
console.log(`${label.padEnd(20)}${value}`);
|
|
413
|
-
|
|
414
|
-
console.log("ARC-402 Daemon Status");
|
|
415
|
-
console.log("─────────────────────");
|
|
416
|
-
line("State:", String(data.state ?? "unknown"));
|
|
417
|
-
line("PID:", String(data.pid ?? "unknown"));
|
|
418
|
-
line("Uptime:", String(data.uptime ?? "unknown"));
|
|
419
|
-
line("Wallet:", String(data.wallet ?? "unknown"));
|
|
420
|
-
line("Machine Key:", String(data.machine_key_address ?? "unknown"));
|
|
421
|
-
console.log();
|
|
422
|
-
console.log("Subsystems:");
|
|
423
420
|
const relayStatus = data.relay_enabled
|
|
424
421
|
? `active — polling ${data.relay_url || "relay"} every ${data.relay_poll_seconds}s`
|
|
425
422
|
: "disabled";
|
|
426
423
|
const watchtowerStatus = data.watchtower_enabled ? "active" : "disabled";
|
|
427
424
|
const bundlerStatus = `${data.bundler_mode} — ${data.bundler_endpoint || "default"}`;
|
|
428
|
-
console.log(` Relay: ${relayStatus}`);
|
|
429
|
-
console.log(` Watchtower: ${watchtowerStatus}`);
|
|
430
|
-
console.log(` Bundler: ${bundlerStatus}`);
|
|
431
|
-
console.log();
|
|
432
425
|
const pending = Number(data.pending_approval ?? 0);
|
|
433
|
-
|
|
434
|
-
|
|
435
|
-
|
|
436
|
-
|
|
437
|
-
|
|
438
|
-
|
|
426
|
+
|
|
427
|
+
console.log(`${c.mark} ARC-402 Daemon Status`);
|
|
428
|
+
console.log();
|
|
429
|
+
renderTree([
|
|
430
|
+
{ label: "State", value: String(data.state ?? "unknown") },
|
|
431
|
+
{ label: "PID", value: String(data.pid ?? "unknown") },
|
|
432
|
+
{ label: "Uptime", value: String(data.uptime ?? "unknown") },
|
|
433
|
+
{ label: "Wallet", value: String(data.wallet ?? "unknown") },
|
|
434
|
+
{ label: "Key", value: String(data.machine_key_address ?? "unknown") },
|
|
435
|
+
{ label: "Relay", value: relayStatus },
|
|
436
|
+
{ label: "Watchtower", value: watchtowerStatus },
|
|
437
|
+
{ label: "Bundler", value: bundlerStatus },
|
|
438
|
+
{ label: "Agreements", value: String(data.active_agreements ?? 0) },
|
|
439
|
+
{
|
|
440
|
+
label: "Pending",
|
|
441
|
+
value: pending > 0 ? `${pending} ← arc402 daemon pending` : "0",
|
|
442
|
+
last: true,
|
|
443
|
+
},
|
|
444
|
+
]);
|
|
439
445
|
}
|
|
440
446
|
|
|
441
447
|
interface HireRow {
|
|
@@ -585,9 +591,9 @@ export function registerDaemonCommands(program: Command): void {
|
|
|
585
591
|
process.exit(0);
|
|
586
592
|
}
|
|
587
593
|
const { configPath, host } = buildOpenShellSshConfig(openShellCfg.sandbox.name);
|
|
588
|
-
|
|
594
|
+
const stopSpinnerRemote = startSpinner(`Stopping daemon (OpenShell PID ${remotePid})...`);
|
|
589
595
|
runCmd("ssh", ["-F", configPath, host, `kill ${remotePid}`], { timeout: 20000 });
|
|
590
|
-
|
|
596
|
+
stopSpinnerRemote.succeed("Stop signal sent");
|
|
591
597
|
return;
|
|
592
598
|
}
|
|
593
599
|
|
|
@@ -597,11 +603,12 @@ export function registerDaemonCommands(program: Command): void {
|
|
|
597
603
|
process.exit(0);
|
|
598
604
|
}
|
|
599
605
|
|
|
600
|
-
|
|
606
|
+
const stopSpinner = startSpinner(`Stopping daemon (PID ${pid})...`);
|
|
601
607
|
const stopped = await stopDaemon({ wait: true });
|
|
602
608
|
if (stopped) {
|
|
603
|
-
|
|
609
|
+
stopSpinner.succeed("Daemon stopped");
|
|
604
610
|
} else {
|
|
611
|
+
stopSpinner.fail("Failed to stop daemon cleanly");
|
|
605
612
|
console.error("Failed to stop daemon cleanly.");
|
|
606
613
|
process.exit(1);
|
|
607
614
|
}
|
|
@@ -656,15 +663,15 @@ export function registerDaemonCommands(program: Command): void {
|
|
|
656
663
|
console.log("Launch path: arc402 openshell init, then arc402 daemon start");
|
|
657
664
|
process.exit(1);
|
|
658
665
|
}
|
|
659
|
-
console.log(
|
|
660
|
-
console.log("─────────────────────");
|
|
661
|
-
console.log(`State: running (OpenShell sandbox)`);
|
|
662
|
-
console.log(`PID: ${remotePid}`);
|
|
663
|
-
console.log(`Sandbox: ${openShellCfg.sandbox.name}`);
|
|
664
|
-
console.log(`Runtime root: ${openShellCfg.runtime?.remote_root ?? DEFAULT_RUNTIME_REMOTE_ROOT}`);
|
|
665
|
-
console.log(`Log path: ${REMOTE_DAEMON_LOG}`);
|
|
666
|
+
console.log(`${c.mark} ARC-402 Daemon Status`);
|
|
666
667
|
console.log();
|
|
667
|
-
|
|
668
|
+
renderTree([
|
|
669
|
+
{ label: "State", value: "running (OpenShell sandbox)" },
|
|
670
|
+
{ label: "PID", value: String(remotePid) },
|
|
671
|
+
{ label: "Sandbox", value: openShellCfg.sandbox.name },
|
|
672
|
+
{ label: "Runtime", value: openShellCfg.runtime?.remote_root ?? DEFAULT_RUNTIME_REMOTE_ROOT },
|
|
673
|
+
{ label: "Log", value: REMOTE_DAEMON_LOG, last: true },
|
|
674
|
+
]);
|
|
668
675
|
return;
|
|
669
676
|
}
|
|
670
677
|
|
package/src/commands/endpoint.ts
CHANGED
|
@@ -17,6 +17,7 @@ import * as dns from "dns/promises";
|
|
|
17
17
|
import * as fs from "fs";
|
|
18
18
|
import * as net from "net";
|
|
19
19
|
import chalk from "chalk";
|
|
20
|
+
import { c } from '../ui/colors';
|
|
20
21
|
|
|
21
22
|
interface DoctorCheck {
|
|
22
23
|
layer: string;
|
|
@@ -477,7 +478,7 @@ export function registerEndpointCommands(program: Command): void {
|
|
|
477
478
|
});
|
|
478
479
|
saveEndpointConfig(cfg);
|
|
479
480
|
|
|
480
|
-
console.log(
|
|
481
|
+
console.log(c.success + c.white(' Endpoint scaffold written: ' + ENDPOINT_CONFIG_PATH));
|
|
481
482
|
console.log(` Agent name: ${cfg.agentName}`);
|
|
482
483
|
console.log(` Hostname: ${cfg.hostname}`);
|
|
483
484
|
console.log(` Public URL: ${cfg.publicUrl}`);
|
|
@@ -510,7 +511,7 @@ export function registerEndpointCommands(program: Command): void {
|
|
|
510
511
|
const allGood = checks.every((check) => check.ok);
|
|
511
512
|
const brokenLayers = Array.from(new Set(checks.filter((check) => !check.ok).map((check) => check.layer)));
|
|
512
513
|
|
|
513
|
-
console.log(
|
|
514
|
+
console.log('\n ' + c.mark + c.white(' ARC-402 Endpoint Status'));
|
|
514
515
|
console.log("─────────────────────");
|
|
515
516
|
console.log(`Agent name: ${cfg.agentName}`);
|
|
516
517
|
console.log(`Hostname: ${cfg.hostname}`);
|
|
@@ -571,7 +572,7 @@ export function registerEndpointCommands(program: Command): void {
|
|
|
571
572
|
});
|
|
572
573
|
saveEndpointConfig(cfg);
|
|
573
574
|
|
|
574
|
-
console.log(
|
|
575
|
+
console.log(c.success + c.white(' Endpoint config locked to ' + cfg.publicUrl));
|
|
575
576
|
console.log(` Hostname: ${cfg.hostname}`);
|
|
576
577
|
console.log(` Tunnel target: ${cfg.tunnelTarget}`);
|
|
577
578
|
console.log(` Wallet: ${cfg.walletAddress}`);
|
package/src/commands/feed.ts
CHANGED
package/src/commands/hire.ts
CHANGED
|
@@ -7,6 +7,10 @@ import { hashFile, hashString } from "../utils/hash";
|
|
|
7
7
|
import { parseDuration } from "../utils/time";
|
|
8
8
|
import { printSenderInfo, executeContractWriteViaWallet } from "../wallet-router";
|
|
9
9
|
import { AGENT_REGISTRY_ABI, SERVICE_AGREEMENT_ABI } from "../abis";
|
|
10
|
+
import { c } from '../ui/colors';
|
|
11
|
+
import { startSpinner } from '../ui/spinner';
|
|
12
|
+
import { renderTree, TreeItem } from '../ui/tree';
|
|
13
|
+
import { formatAddress } from '../ui/format';
|
|
10
14
|
|
|
11
15
|
const DEFAULT_REGISTRY_ADDRESS = "0xD5c2851B00090c92Ba7F4723FB548bb30C9B6865";
|
|
12
16
|
|
|
@@ -132,6 +136,8 @@ export function registerHireCommand(program: Command): void {
|
|
|
132
136
|
|
|
133
137
|
let agreementId: bigint;
|
|
134
138
|
|
|
139
|
+
const hireSpinner = startSpinner('Submitting agreement...');
|
|
140
|
+
|
|
135
141
|
if (config.walletContractAddress) {
|
|
136
142
|
// Smart wallet path — wallet handles per-tx USDC approval via maxApprovalAmount
|
|
137
143
|
const tx = await executeContractWriteViaWallet(
|
|
@@ -185,6 +191,8 @@ export function registerHireCommand(program: Command): void {
|
|
|
185
191
|
agreementId = result.agreementId;
|
|
186
192
|
}
|
|
187
193
|
|
|
194
|
+
hireSpinner.succeed('Agreement proposed');
|
|
195
|
+
|
|
188
196
|
// Notify provider's HTTP endpoint (non-blocking)
|
|
189
197
|
const hireRegistryAddress = config.agentRegistryV2Address ?? config.agentRegistryAddress ?? DEFAULT_REGISTRY_ADDRESS;
|
|
190
198
|
try {
|
package/src/commands/owner.ts
CHANGED
|
@@ -2,6 +2,9 @@ import { Command } from "commander";
|
|
|
2
2
|
import { DisputeArbitrationClient } from "@arc402/sdk";
|
|
3
3
|
import { loadConfig } from "../config";
|
|
4
4
|
import { requireSigner } from "../client";
|
|
5
|
+
import { c } from '../ui/colors';
|
|
6
|
+
import { startSpinner } from '../ui/spinner';
|
|
7
|
+
import { formatAddress } from '../ui/format';
|
|
5
8
|
|
|
6
9
|
export function registerOwnerCommands(program: Command): void {
|
|
7
10
|
const owner = program.command("owner").description("Protocol ownership management (DisputeArbitration two-step transfer)");
|
|
@@ -13,8 +16,9 @@ export function registerOwnerCommands(program: Command): void {
|
|
|
13
16
|
if (!config.disputeArbitrationAddress) throw new Error("disputeArbitrationAddress missing in config");
|
|
14
17
|
const { signer } = await requireSigner(config);
|
|
15
18
|
const client = new DisputeArbitrationClient(config.disputeArbitrationAddress, signer);
|
|
19
|
+
const spinner = startSpinner('Proposing ownership transfer…');
|
|
16
20
|
await client.proposeOwner(newOwner);
|
|
17
|
-
|
|
21
|
+
spinner.succeed(c.success + c.white(' Ownership transfer proposed to ' + formatAddress(newOwner)));
|
|
18
22
|
});
|
|
19
23
|
|
|
20
24
|
owner.command("accept-transfer")
|
package/src/commands/policy.ts
CHANGED
|
@@ -2,6 +2,9 @@ import { Command } from "commander";
|
|
|
2
2
|
import { ethers } from "ethers";
|
|
3
3
|
import { loadConfig } from "../config";
|
|
4
4
|
import { getClient, requireSigner } from "../client";
|
|
5
|
+
import { c } from '../ui/colors';
|
|
6
|
+
import { startSpinner } from '../ui/spinner';
|
|
7
|
+
import { formatAddress } from '../ui/format';
|
|
5
8
|
|
|
6
9
|
const POLICY_ENGINE_EXTENDED_ABI = [
|
|
7
10
|
"function addToBlocklist(address wallet, address provider) external",
|
package/src/commands/relay.ts
CHANGED
|
@@ -3,6 +3,8 @@ import { ProviderResponseType, ServiceAgreementClient } from "@arc402/sdk";
|
|
|
3
3
|
import { loadConfig } from "../config";
|
|
4
4
|
import { getClient, requireSigner } from "../client";
|
|
5
5
|
import { hashFile, hashString } from "../utils/hash";
|
|
6
|
+
import { c } from '../ui/colors';
|
|
7
|
+
import { startSpinner } from '../ui/spinner';
|
|
6
8
|
|
|
7
9
|
export function registerRemediateCommands(program: Command): void {
|
|
8
10
|
const remediate = program.command("remediate").description("Negotiated remediation before formal dispute");
|
|
@@ -3,6 +3,10 @@ import { ReputationOracleClient, ReputationSignalType } from "@arc402/sdk";
|
|
|
3
3
|
import { ethers } from "ethers";
|
|
4
4
|
import { loadConfig } from "../config";
|
|
5
5
|
import { getClient, requireSigner } from "../client";
|
|
6
|
+
import { c } from '../ui/colors';
|
|
7
|
+
import { startSpinner } from '../ui/spinner';
|
|
8
|
+
import { renderTree } from '../ui/tree';
|
|
9
|
+
import { formatAddress } from '../ui/format';
|
|
6
10
|
|
|
7
11
|
const reputation = new Command("reputation").description("Network-wide reputation signals");
|
|
8
12
|
|
package/src/commands/trust.ts
CHANGED
|
@@ -3,6 +3,9 @@ import { ReputationOracleClient, SponsorshipAttestationClient, TrustClient } fro
|
|
|
3
3
|
import { loadConfig } from "../config";
|
|
4
4
|
import { getClient } from "../client";
|
|
5
5
|
import { getTrustTier, identityTierLabel } from "../utils/format";
|
|
6
|
+
import { c } from '../ui/colors';
|
|
7
|
+
import { renderTree } from '../ui/tree';
|
|
8
|
+
import { formatAddress } from '../ui/format';
|
|
6
9
|
|
|
7
10
|
export function registerTrustCommand(program: Command): void {
|
|
8
11
|
program.command("trust <address>").description("Look up trust plus secondary sponsorship/reputation signals for an address").option("--json").action(async (address, opts) => {
|
package/src/commands/verify.ts
CHANGED
|
@@ -5,6 +5,8 @@ import { loadConfig } from "../config";
|
|
|
5
5
|
import { getClient, requireSigner } from "../client";
|
|
6
6
|
import { printSenderInfo, executeContractWriteViaWallet } from "../wallet-router";
|
|
7
7
|
import { SERVICE_AGREEMENT_ABI } from "../abis";
|
|
8
|
+
import { c } from '../ui/colors';
|
|
9
|
+
import { startSpinner } from '../ui/spinner';
|
|
8
10
|
|
|
9
11
|
// Agreement status values from the contract
|
|
10
12
|
const AGREEMENT_STATUS_NAMES: Record<number, string> = {
|