arc402-cli 0.9.18 → 0.10.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +41 -2
- package/dist/abis.d.ts +1 -0
- package/dist/abis.d.ts.map +1 -1
- package/dist/abis.js +45 -14
- package/dist/abis.js.map +1 -1
- package/dist/bundler.d.ts +1 -1
- package/dist/bundler.d.ts.map +1 -1
- package/dist/bundler.js +61 -27
- package/dist/bundler.js.map +1 -1
- package/dist/client.d.ts +1 -1
- package/dist/client.d.ts.map +1 -1
- package/dist/client.js +9 -5
- package/dist/client.js.map +1 -1
- package/dist/coinbase-smart-wallet.js +4 -1
- package/dist/coinbase-smart-wallet.js.map +1 -1
- package/dist/commands/accept.js +28 -25
- package/dist/commands/accept.js.map +1 -1
- package/dist/commands/agent-handshake.js +18 -15
- package/dist/commands/agent-handshake.js.map +1 -1
- package/dist/commands/agent.js +104 -98
- package/dist/commands/agent.js.map +1 -1
- package/dist/commands/agreements.js +98 -62
- package/dist/commands/agreements.js.map +1 -1
- package/dist/commands/arbitrator.js +81 -45
- package/dist/commands/arbitrator.js.map +1 -1
- package/dist/commands/arena-handshake.d.ts.map +1 -1
- package/dist/commands/arena-handshake.js +35 -53
- package/dist/commands/arena-handshake.js.map +1 -1
- package/dist/commands/arena.js +18 -12
- package/dist/commands/arena.js.map +1 -1
- package/dist/commands/backup.js +36 -30
- package/dist/commands/backup.js.map +1 -1
- package/dist/commands/cancel.js +18 -15
- package/dist/commands/cancel.js.map +1 -1
- package/dist/commands/channel.js +81 -45
- package/dist/commands/channel.js.map +1 -1
- package/dist/commands/coldstart.js +34 -31
- package/dist/commands/coldstart.js.map +1 -1
- package/dist/commands/compute.d.ts +14 -0
- package/dist/commands/compute.d.ts.map +1 -0
- package/dist/commands/compute.js +466 -0
- package/dist/commands/compute.js.map +1 -0
- package/dist/commands/config.js +30 -24
- package/dist/commands/config.js.map +1 -1
- package/dist/commands/contract-interaction.js +15 -12
- package/dist/commands/contract-interaction.js.map +1 -1
- package/dist/commands/daemon.d.ts.map +1 -1
- package/dist/commands/daemon.js +135 -98
- package/dist/commands/daemon.js.map +1 -1
- package/dist/commands/deliver.js +76 -37
- package/dist/commands/deliver.js.map +1 -1
- package/dist/commands/discover.js +27 -24
- package/dist/commands/discover.js.map +1 -1
- package/dist/commands/dispute.js +110 -104
- package/dist/commands/dispute.js.map +1 -1
- package/dist/commands/doctor.js +55 -16
- package/dist/commands/doctor.js.map +1 -1
- package/dist/commands/endpoint.js +95 -56
- package/dist/commands/endpoint.js.map +1 -1
- package/dist/commands/feed.js +18 -11
- package/dist/commands/feed.js.map +1 -1
- package/dist/commands/hire.js +40 -37
- package/dist/commands/hire.js.map +1 -1
- package/dist/commands/migrate.js +33 -30
- package/dist/commands/migrate.js.map +1 -1
- package/dist/commands/negotiate.d.ts.map +1 -1
- package/dist/commands/negotiate.js +36 -34
- package/dist/commands/negotiate.js.map +1 -1
- package/dist/commands/openshell.js +104 -68
- package/dist/commands/openshell.js.map +1 -1
- package/dist/commands/owner.js +20 -17
- package/dist/commands/owner.js.map +1 -1
- package/dist/commands/policy.js +43 -41
- package/dist/commands/policy.js.map +1 -1
- package/dist/commands/relay.d.ts.map +1 -1
- package/dist/commands/relay.js +51 -18
- package/dist/commands/relay.js.map +1 -1
- package/dist/commands/remediate.js +23 -20
- package/dist/commands/remediate.js.map +1 -1
- package/dist/commands/reputation.js +27 -25
- package/dist/commands/reputation.js.map +1 -1
- package/dist/commands/setup.js +104 -65
- package/dist/commands/setup.js.map +1 -1
- package/dist/commands/trust.js +20 -17
- package/dist/commands/trust.js.map +1 -1
- package/dist/commands/verify.js +21 -18
- package/dist/commands/verify.js.map +1 -1
- package/dist/commands/wallet.d.ts.map +1 -1
- package/dist/commands/wallet.js +645 -679
- package/dist/commands/wallet.js.map +1 -1
- package/dist/commands/watch.js +36 -33
- package/dist/commands/watch.js.map +1 -1
- package/dist/commands/watchtower.js +73 -37
- package/dist/commands/watchtower.js.map +1 -1
- package/dist/commands/workroom.d.ts.map +1 -1
- package/dist/commands/workroom.js +282 -143
- package/dist/commands/workroom.js.map +1 -1
- package/dist/config.d.ts +3 -0
- package/dist/config.d.ts.map +1 -1
- package/dist/config.js +71 -22
- package/dist/config.js.map +1 -1
- package/dist/daemon/compute-metering.d.ts +61 -0
- package/dist/daemon/compute-metering.d.ts.map +1 -0
- package/dist/daemon/compute-metering.js +299 -0
- package/dist/daemon/compute-metering.js.map +1 -0
- package/dist/daemon/compute-session.d.ts +100 -0
- package/dist/daemon/compute-session.d.ts.map +1 -0
- package/dist/daemon/compute-session.js +231 -0
- package/dist/daemon/compute-session.js.map +1 -0
- package/dist/daemon/config.d.ts +19 -1
- package/dist/daemon/config.d.ts.map +1 -1
- package/dist/daemon/config.js +90 -16
- package/dist/daemon/config.js.map +1 -1
- package/dist/daemon/credentials.d.ts +24 -0
- package/dist/daemon/credentials.d.ts.map +1 -0
- package/dist/daemon/credentials.js +80 -0
- package/dist/daemon/credentials.js.map +1 -0
- package/dist/daemon/delivery-client.d.ts +35 -0
- package/dist/daemon/delivery-client.d.ts.map +1 -0
- package/dist/daemon/delivery-client.js +231 -0
- package/dist/daemon/delivery-client.js.map +1 -0
- package/dist/daemon/file-delivery.d.ts +98 -0
- package/dist/daemon/file-delivery.d.ts.map +1 -0
- package/dist/daemon/file-delivery.js +461 -0
- package/dist/daemon/file-delivery.js.map +1 -0
- package/dist/daemon/hire-listener.d.ts +3 -3
- package/dist/daemon/hire-listener.d.ts.map +1 -1
- package/dist/daemon/hire-listener.js +47 -13
- package/dist/daemon/hire-listener.js.map +1 -1
- package/dist/daemon/index.d.ts +2 -1
- package/dist/daemon/index.d.ts.map +1 -1
- package/dist/daemon/index.js +526 -53
- package/dist/daemon/index.js.map +1 -1
- package/dist/daemon/job-lifecycle.d.ts +1 -1
- package/dist/daemon/job-lifecycle.d.ts.map +1 -1
- package/dist/daemon/job-lifecycle.js +51 -11
- package/dist/daemon/job-lifecycle.js.map +1 -1
- package/dist/daemon/notify.d.ts +1 -1
- package/dist/daemon/notify.d.ts.map +1 -1
- package/dist/daemon/notify.js +53 -19
- package/dist/daemon/notify.js.map +1 -1
- package/dist/daemon/token-metering.js +47 -8
- package/dist/daemon/token-metering.js.map +1 -1
- package/dist/daemon/userops.d.ts +2 -2
- package/dist/daemon/userops.d.ts.map +1 -1
- package/dist/daemon/userops.js +27 -23
- package/dist/daemon/userops.js.map +1 -1
- package/dist/daemon/wallet-monitor.d.ts +1 -1
- package/dist/daemon/wallet-monitor.d.ts.map +1 -1
- package/dist/daemon/wallet-monitor.js +12 -8
- package/dist/daemon/wallet-monitor.js.map +1 -1
- package/dist/daemon/worker-executor.d.ts +71 -0
- package/dist/daemon/worker-executor.d.ts.map +1 -0
- package/dist/daemon/worker-executor.js +382 -0
- package/dist/daemon/worker-executor.js.map +1 -0
- package/dist/drain-v4.js +64 -26
- package/dist/drain-v4.js.map +1 -1
- package/dist/endpoint-config.js +63 -20
- package/dist/endpoint-config.js.map +1 -1
- package/dist/endpoint-notify.js +48 -9
- package/dist/endpoint-notify.js.map +1 -1
- package/dist/index.js +50 -18
- package/dist/index.js.map +1 -1
- package/dist/openshell-runtime.d.ts.map +1 -1
- package/dist/openshell-runtime.js +82 -38
- package/dist/openshell-runtime.js.map +1 -1
- package/dist/program.d.ts.map +1 -1
- package/dist/program.js +85 -78
- package/dist/program.js.map +1 -1
- package/dist/repl.js +31 -25
- package/dist/repl.js.map +1 -1
- package/dist/signing.js +6 -3
- package/dist/signing.js.map +1 -1
- package/dist/telegram-notify.js +40 -3
- package/dist/telegram-notify.js.map +1 -1
- package/dist/tui/App.d.ts.map +1 -1
- package/dist/tui/App.js +56 -89
- package/dist/tui/App.js.map +1 -1
- package/dist/tui/Footer.js +7 -4
- package/dist/tui/Footer.js.map +1 -1
- package/dist/tui/Header.d.ts +1 -1
- package/dist/tui/Header.d.ts.map +1 -1
- package/dist/tui/Header.js +14 -9
- package/dist/tui/Header.js.map +1 -1
- package/dist/tui/InputLine.d.ts +2 -1
- package/dist/tui/InputLine.d.ts.map +1 -1
- package/dist/tui/InputLine.js +47 -97
- package/dist/tui/InputLine.js.map +1 -1
- package/dist/tui/Viewport.d.ts +1 -2
- package/dist/tui/Viewport.d.ts.map +1 -1
- package/dist/tui/Viewport.js +26 -6
- package/dist/tui/Viewport.js.map +1 -1
- package/dist/tui/WalletConnectPairing.js +19 -16
- package/dist/tui/WalletConnectPairing.js.map +1 -1
- package/dist/tui/components/Button.js +9 -6
- package/dist/tui/components/Button.js.map +1 -1
- package/dist/tui/components/CeremonyView.js +8 -5
- package/dist/tui/components/CeremonyView.js.map +1 -1
- package/dist/tui/components/CompletionDropdown.js +9 -6
- package/dist/tui/components/CompletionDropdown.js.map +1 -1
- package/dist/tui/components/ConfirmPrompt.js +8 -5
- package/dist/tui/components/ConfirmPrompt.js.map +1 -1
- package/dist/tui/components/CustomTextInput.js +14 -11
- package/dist/tui/components/CustomTextInput.js.map +1 -1
- package/dist/tui/components/InteractiveTable.js +12 -9
- package/dist/tui/components/InteractiveTable.js.map +1 -1
- package/dist/tui/components/StepSpinner.js +13 -10
- package/dist/tui/components/StepSpinner.js.map +1 -1
- package/dist/tui/components/Toast.js +12 -8
- package/dist/tui/components/Toast.js.map +1 -1
- package/dist/tui/index.d.ts.map +1 -1
- package/dist/tui/index.js +21 -28
- package/dist/tui/index.js.map +1 -1
- package/dist/tui/useChat.js +19 -13
- package/dist/tui/useChat.js.map +1 -1
- package/dist/tui/useCommand.d.ts +2 -3
- package/dist/tui/useCommand.d.ts.map +1 -1
- package/dist/tui/useCommand.js +24 -100
- package/dist/tui/useCommand.js.map +1 -1
- package/dist/tui/useNotifications.js +8 -5
- package/dist/tui/useNotifications.js.map +1 -1
- package/dist/tui/useScroll.d.ts.map +1 -1
- package/dist/tui/useScroll.js +12 -15
- package/dist/tui/useScroll.js.map +1 -1
- package/dist/ui/banner.d.ts +0 -12
- package/dist/ui/banner.d.ts.map +1 -1
- package/dist/ui/banner.js +19 -35
- package/dist/ui/banner.js.map +1 -1
- package/dist/ui/colors.js +19 -13
- package/dist/ui/colors.js.map +1 -1
- package/dist/ui/format.js +14 -6
- package/dist/ui/format.js.map +1 -1
- package/dist/ui/qr-render.js +11 -4
- package/dist/ui/qr-render.js.map +1 -1
- package/dist/ui/rpc-fallback.js +11 -6
- package/dist/ui/rpc-fallback.js.map +1 -1
- package/dist/ui/spinner.js +12 -6
- package/dist/ui/spinner.js.map +1 -1
- package/dist/ui/tree.js +6 -3
- package/dist/ui/tree.js.map +1 -1
- package/dist/utils/format.js +41 -27
- package/dist/utils/format.js.map +1 -1
- package/dist/utils/hash.js +42 -4
- package/dist/utils/hash.js.map +1 -1
- package/dist/utils/time.js +6 -2
- package/dist/utils/time.js.map +1 -1
- package/dist/wallet-router.d.ts +1 -1
- package/dist/wallet-router.d.ts.map +1 -1
- package/dist/wallet-router.js +19 -12
- package/dist/wallet-router.js.map +1 -1
- package/dist/walletconnect-session.d.ts +1 -1
- package/dist/walletconnect-session.d.ts.map +1 -1
- package/dist/walletconnect-session.js +11 -6
- package/dist/walletconnect-session.js.map +1 -1
- package/dist/walletconnect.d.ts +5 -6
- package/dist/walletconnect.d.ts.map +1 -1
- package/dist/walletconnect.js +35 -32
- package/dist/walletconnect.js.map +1 -1
- package/package.json +11 -10
- package/INK6-UX-SPEC.md +0 -446
- package/MIGRATION-SPEC.md +0 -108
- package/TUI-SPEC.md +0 -214
- package/scripts/authorize-machine-key.ts +0 -43
- package/scripts/drain-wallet.ts +0 -149
- package/scripts/execute-spend-only.ts +0 -81
- package/scripts/register-agent-userop.ts +0 -186
- package/src/abis.ts +0 -187
- package/src/bundler.ts +0 -235
- package/src/client.ts +0 -36
- package/src/coinbase-smart-wallet.ts +0 -51
- package/src/commands/accept.ts +0 -64
- package/src/commands/agent-handshake.ts +0 -72
- package/src/commands/agent.ts +0 -691
- package/src/commands/agreements.ts +0 -350
- package/src/commands/arbitrator.ts +0 -180
- package/src/commands/arena-handshake.ts +0 -274
- package/src/commands/arena.ts +0 -122
- package/src/commands/backup.ts +0 -117
- package/src/commands/cancel.ts +0 -35
- package/src/commands/channel.ts +0 -218
- package/src/commands/coldstart.ts +0 -165
- package/src/commands/config.ts +0 -68
- package/src/commands/contract-interaction.ts +0 -166
- package/src/commands/daemon.ts +0 -1054
- package/src/commands/deliver.ts +0 -148
- package/src/commands/discover.ts +0 -350
- package/src/commands/dispute.ts +0 -375
- package/src/commands/doctor.ts +0 -172
- package/src/commands/endpoint.ts +0 -620
- package/src/commands/feed.ts +0 -229
- package/src/commands/hire.ts +0 -245
- package/src/commands/migrate.ts +0 -177
- package/src/commands/negotiate.ts +0 -272
- package/src/commands/openshell.ts +0 -1055
- package/src/commands/owner.ts +0 -35
- package/src/commands/policy.ts +0 -263
- package/src/commands/relay.ts +0 -277
- package/src/commands/remediate.ts +0 -24
- package/src/commands/reputation.ts +0 -79
- package/src/commands/setup.ts +0 -343
- package/src/commands/trust.ts +0 -27
- package/src/commands/verify.ts +0 -91
- package/src/commands/wallet.ts +0 -3548
- package/src/commands/watch.ts +0 -220
- package/src/commands/watchtower.ts +0 -248
- package/src/commands/workroom.ts +0 -963
- package/src/config.ts +0 -220
- package/src/daemon/config.ts +0 -344
- package/src/daemon/hire-listener.ts +0 -226
- package/src/daemon/index.ts +0 -1089
- package/src/daemon/job-lifecycle.ts +0 -215
- package/src/daemon/notify.ts +0 -297
- package/src/daemon/token-metering.ts +0 -183
- package/src/daemon/userops.ts +0 -119
- package/src/daemon/wallet-monitor.ts +0 -90
- package/src/drain-v4.ts +0 -159
- package/src/endpoint-config.ts +0 -83
- package/src/endpoint-notify.ts +0 -129
- package/src/index.ts +0 -74
- package/src/openshell-runtime.ts +0 -281
- package/src/program.ts +0 -88
- package/src/repl.ts +0 -178
- package/src/signing.ts +0 -28
- package/src/telegram-notify.ts +0 -88
- package/src/tui/App.tsx +0 -263
- package/src/tui/Footer.tsx +0 -18
- package/src/tui/Header.tsx +0 -45
- package/src/tui/InputLine.tsx +0 -243
- package/src/tui/Viewport.tsx +0 -51
- package/src/tui/WalletConnectPairing.tsx +0 -114
- package/src/tui/components/Button.tsx +0 -38
- package/src/tui/components/CeremonyView.tsx +0 -39
- package/src/tui/components/CompletionDropdown.tsx +0 -56
- package/src/tui/components/ConfirmPrompt.tsx +0 -36
- package/src/tui/components/CustomTextInput.tsx +0 -132
- package/src/tui/components/InteractiveTable.tsx +0 -106
- package/src/tui/components/StepSpinner.tsx +0 -84
- package/src/tui/components/Toast.tsx +0 -59
- package/src/tui/index.tsx +0 -90
- package/src/tui/useChat.ts +0 -103
- package/src/tui/useCommand.ts +0 -238
- package/src/tui/useNotifications.ts +0 -28
- package/src/tui/useScroll.ts +0 -69
- package/src/ui/banner.ts +0 -78
- package/src/ui/colors.ts +0 -30
- package/src/ui/format.ts +0 -78
- package/src/ui/qr-render.ts +0 -92
- package/src/ui/rpc-fallback.ts +0 -59
- package/src/ui/spinner.ts +0 -56
- package/src/ui/tree.ts +0 -16
- package/src/utils/format.ts +0 -48
- package/src/utils/hash.ts +0 -5
- package/src/utils/time.ts +0 -15
- package/src/wallet-router.ts +0 -178
- package/src/walletconnect-session.ts +0 -27
- package/src/walletconnect.ts +0 -309
- package/test/time.test.js +0 -11
- package/tsconfig.json +0 -33
package/src/commands/owner.ts
DELETED
|
@@ -1,35 +0,0 @@
|
|
|
1
|
-
import { Command } from "commander";
|
|
2
|
-
import { DisputeArbitrationClient } from "@arc402/sdk";
|
|
3
|
-
import { loadConfig } from "../config.js";
|
|
4
|
-
import { requireSigner } from "../client.js";
|
|
5
|
-
import { c } from '../ui/colors.js';
|
|
6
|
-
import { startSpinner } from '../ui/spinner.js';
|
|
7
|
-
import { formatAddress } from '../ui/format.js';
|
|
8
|
-
|
|
9
|
-
export function registerOwnerCommands(program: Command): void {
|
|
10
|
-
const owner = program.command("owner").description("Protocol ownership management (DisputeArbitration two-step transfer)");
|
|
11
|
-
|
|
12
|
-
owner.command("propose-transfer <newOwner>")
|
|
13
|
-
.description("Step 1: Propose ownership transfer of DisputeArbitration to a new address. New owner must call accept-transfer to complete.")
|
|
14
|
-
.action(async (newOwner, _opts) => {
|
|
15
|
-
const config = loadConfig();
|
|
16
|
-
if (!config.disputeArbitrationAddress) throw new Error("disputeArbitrationAddress missing in config");
|
|
17
|
-
const { signer } = await requireSigner(config);
|
|
18
|
-
const client = new DisputeArbitrationClient(config.disputeArbitrationAddress, signer);
|
|
19
|
-
const spinner = startSpinner('Proposing ownership transfer…');
|
|
20
|
-
await client.proposeOwner(newOwner);
|
|
21
|
-
spinner.succeed(c.success + c.white(' Ownership transfer proposed to ' + formatAddress(newOwner)));
|
|
22
|
-
});
|
|
23
|
-
|
|
24
|
-
owner.command("accept-transfer")
|
|
25
|
-
.description("Step 2: Accept pending ownership of DisputeArbitration. Must be called from the pending owner's key.")
|
|
26
|
-
.action(async (_opts) => {
|
|
27
|
-
const config = loadConfig();
|
|
28
|
-
if (!config.disputeArbitrationAddress) throw new Error("disputeArbitrationAddress missing in config");
|
|
29
|
-
const { signer } = await requireSigner(config);
|
|
30
|
-
const client = new DisputeArbitrationClient(config.disputeArbitrationAddress, signer);
|
|
31
|
-
const spinner = startSpinner('Accepting ownership…');
|
|
32
|
-
await client.acceptOwnership();
|
|
33
|
-
spinner.succeed(c.success + c.white(' Ownership accepted'));
|
|
34
|
-
});
|
|
35
|
-
}
|
package/src/commands/policy.ts
DELETED
|
@@ -1,263 +0,0 @@
|
|
|
1
|
-
import { Command } from "commander";
|
|
2
|
-
import { ethers } from "ethers";
|
|
3
|
-
import { loadConfig } from "../config.js";
|
|
4
|
-
import { getClient, requireSigner } from "../client.js";
|
|
5
|
-
import { c } from '../ui/colors.js';
|
|
6
|
-
import { startSpinner } from '../ui/spinner.js';
|
|
7
|
-
import { formatAddress } from '../ui/format.js';
|
|
8
|
-
|
|
9
|
-
const POLICY_ENGINE_EXTENDED_ABI = [
|
|
10
|
-
"function addToBlocklist(address wallet, address provider) external",
|
|
11
|
-
"function removeFromBlocklist(address wallet, address provider) external",
|
|
12
|
-
"function isBlocked(address wallet, address provider) external view returns (bool)",
|
|
13
|
-
"function addPreferred(address wallet, string capability, address provider) external",
|
|
14
|
-
"function removePreferred(address wallet, string capability, address provider) external",
|
|
15
|
-
"function getPreferred(address wallet, string capability) external view returns (address[])",
|
|
16
|
-
"function isPreferred(address wallet, string capability, address provider) external view returns (bool)",
|
|
17
|
-
"event ProviderBlocked(address indexed wallet, address indexed provider)",
|
|
18
|
-
"event ProviderUnblocked(address indexed wallet, address indexed provider)",
|
|
19
|
-
"event ProviderPreferred(address indexed wallet, address indexed provider, string capability)",
|
|
20
|
-
"event ProviderUnpreferred(address indexed wallet, address indexed provider, string capability)",
|
|
21
|
-
] as const;
|
|
22
|
-
|
|
23
|
-
function getPolicyEngine(address: string, runner: ethers.ContractRunner) {
|
|
24
|
-
return new ethers.Contract(address, POLICY_ENGINE_EXTENDED_ABI, runner);
|
|
25
|
-
}
|
|
26
|
-
|
|
27
|
-
const policy = new Command("policy").description("Personal policy enforcement: blocklist and shortlist");
|
|
28
|
-
|
|
29
|
-
// ─── blocklist ────────────────────────────────────────────────────────────────
|
|
30
|
-
|
|
31
|
-
const blocklist = policy.command("blocklist").description("Hard-stop blocklist: addresses your agent will never accept work from");
|
|
32
|
-
|
|
33
|
-
blocklist
|
|
34
|
-
.command("add <address>")
|
|
35
|
-
.description("Block a provider address")
|
|
36
|
-
.option("--json")
|
|
37
|
-
.action(async (address, opts) => {
|
|
38
|
-
const config = loadConfig();
|
|
39
|
-
if (!config.policyEngineAddress) {
|
|
40
|
-
console.error("policyEngineAddress not configured. Run `arc402 config set policyEngineAddress <address>`.");
|
|
41
|
-
process.exit(1);
|
|
42
|
-
}
|
|
43
|
-
const { signer, address: wallet } = await requireSigner(config);
|
|
44
|
-
const contract = getPolicyEngine(config.policyEngineAddress, signer);
|
|
45
|
-
const already = await contract.isBlocked(wallet, address);
|
|
46
|
-
if (already) {
|
|
47
|
-
if (opts.json) return console.log(JSON.stringify({ address, blocked: true, alreadyBlocked: true }));
|
|
48
|
-
return console.log(' ' + c.dim('Already blocked: ' + formatAddress(address)));
|
|
49
|
-
}
|
|
50
|
-
await (await contract.addToBlocklist(wallet, address)).wait();
|
|
51
|
-
if (opts.json) return console.log(JSON.stringify({ address, blocked: true }));
|
|
52
|
-
console.log(' ' + c.success + c.white(' Blocked: ' + formatAddress(address)));
|
|
53
|
-
});
|
|
54
|
-
|
|
55
|
-
blocklist
|
|
56
|
-
.command("remove <address>")
|
|
57
|
-
.description("Remove a provider from your blocklist")
|
|
58
|
-
.option("--json")
|
|
59
|
-
.action(async (address, opts) => {
|
|
60
|
-
const config = loadConfig();
|
|
61
|
-
if (!config.policyEngineAddress) {
|
|
62
|
-
console.error("policyEngineAddress not configured. Run `arc402 config set policyEngineAddress <address>`.");
|
|
63
|
-
process.exit(1);
|
|
64
|
-
}
|
|
65
|
-
const { signer, address: wallet } = await requireSigner(config);
|
|
66
|
-
const contract = getPolicyEngine(config.policyEngineAddress, signer);
|
|
67
|
-
const isBlockedNow = await contract.isBlocked(wallet, address);
|
|
68
|
-
if (!isBlockedNow) {
|
|
69
|
-
if (opts.json) return console.log(JSON.stringify({ address, blocked: false, notBlocked: true }));
|
|
70
|
-
return console.log(' ' + c.dim('Not on blocklist: ' + formatAddress(address)));
|
|
71
|
-
}
|
|
72
|
-
await (await contract.removeFromBlocklist(wallet, address)).wait();
|
|
73
|
-
if (opts.json) return console.log(JSON.stringify({ address, blocked: false }));
|
|
74
|
-
console.log(' ' + c.success + c.white(' Unblocked: ' + formatAddress(address)));
|
|
75
|
-
});
|
|
76
|
-
|
|
77
|
-
blocklist
|
|
78
|
-
.command("check <address>")
|
|
79
|
-
.description("Check if an address is on your blocklist")
|
|
80
|
-
.option("--json")
|
|
81
|
-
.action(async (address, opts) => {
|
|
82
|
-
const config = loadConfig();
|
|
83
|
-
if (!config.policyEngineAddress) {
|
|
84
|
-
console.error("policyEngineAddress not configured.");
|
|
85
|
-
process.exit(1);
|
|
86
|
-
}
|
|
87
|
-
const { provider } = await getClient(config);
|
|
88
|
-
const { address: wallet } = await requireSigner(config);
|
|
89
|
-
const contract = getPolicyEngine(config.policyEngineAddress, provider);
|
|
90
|
-
const blocked = await contract.isBlocked(wallet, address);
|
|
91
|
-
if (opts.json) return console.log(JSON.stringify({ address, blocked }));
|
|
92
|
-
if (blocked) {
|
|
93
|
-
console.log(' ' + c.warning + c.white(' ' + formatAddress(address) + ' is BLOCKED'));
|
|
94
|
-
} else {
|
|
95
|
-
console.log(' ' + c.success + c.white(' ' + formatAddress(address) + ' is not blocked'));
|
|
96
|
-
}
|
|
97
|
-
});
|
|
98
|
-
|
|
99
|
-
blocklist
|
|
100
|
-
.command("list")
|
|
101
|
-
.description("List all addresses on your blocklist (scans on-chain events)")
|
|
102
|
-
.option("--from-block <n>", "Start block for event log query (default: latest-9000 to stay within public RPC limits)")
|
|
103
|
-
.option("--json")
|
|
104
|
-
.action(async (opts) => {
|
|
105
|
-
const config = loadConfig();
|
|
106
|
-
if (!config.policyEngineAddress) {
|
|
107
|
-
console.error("policyEngineAddress not configured.");
|
|
108
|
-
process.exit(1);
|
|
109
|
-
}
|
|
110
|
-
const { provider } = await getClient(config);
|
|
111
|
-
const { address: wallet } = await requireSigner(config);
|
|
112
|
-
const contract = getPolicyEngine(config.policyEngineAddress, provider);
|
|
113
|
-
|
|
114
|
-
const latestBlock = await provider.getBlockNumber();
|
|
115
|
-
const fromBlock = opts.fromBlock !== undefined ? parseInt(opts.fromBlock, 10) : Math.max(0, latestBlock - 9000);
|
|
116
|
-
|
|
117
|
-
const [blockedEvents, unblockedEvents] = await Promise.all([
|
|
118
|
-
contract.queryFilter(contract.filters.ProviderBlocked(wallet), fromBlock),
|
|
119
|
-
contract.queryFilter(contract.filters.ProviderUnblocked(wallet), fromBlock),
|
|
120
|
-
]);
|
|
121
|
-
const unblocked = new Set(
|
|
122
|
-
unblockedEvents.map((e) => (e as ethers.EventLog).args.provider.toLowerCase())
|
|
123
|
-
);
|
|
124
|
-
const addresses = blockedEvents
|
|
125
|
-
.map((e) => (e as ethers.EventLog).args.provider as string)
|
|
126
|
-
.filter((p) => !unblocked.has(p.toLowerCase()));
|
|
127
|
-
|
|
128
|
-
if (opts.json) return console.log(JSON.stringify({ wallet, blocked: addresses }, null, 2));
|
|
129
|
-
if (addresses.length === 0) return console.log("No addresses on your blocklist");
|
|
130
|
-
addresses.forEach((a) => console.log(a));
|
|
131
|
-
});
|
|
132
|
-
|
|
133
|
-
// ─── shortlist ────────────────────────────────────────────────────────────────
|
|
134
|
-
|
|
135
|
-
const shortlist = policy.command("shortlist").description("Preferred providers per capability (preferred or exclusive)");
|
|
136
|
-
|
|
137
|
-
shortlist
|
|
138
|
-
.command("add <address>")
|
|
139
|
-
.description("Add a provider to your shortlist for a capability")
|
|
140
|
-
.requiredOption("--capability <name>", "Capability name (e.g. code.review)")
|
|
141
|
-
.option("--note <text>", "Optional note (stored off-chain only)")
|
|
142
|
-
.option("--json")
|
|
143
|
-
.action(async (address, opts) => {
|
|
144
|
-
const config = loadConfig();
|
|
145
|
-
if (!config.policyEngineAddress) {
|
|
146
|
-
console.error("policyEngineAddress not configured. Run `arc402 config set policyEngineAddress <address>`.");
|
|
147
|
-
process.exit(1);
|
|
148
|
-
}
|
|
149
|
-
const { signer, address: wallet } = await requireSigner(config);
|
|
150
|
-
const contract = getPolicyEngine(config.policyEngineAddress, signer);
|
|
151
|
-
const alreadyPreferred = await contract.isPreferred(wallet, opts.capability, address);
|
|
152
|
-
if (alreadyPreferred) {
|
|
153
|
-
if (opts.json) return console.log(JSON.stringify({ address, capability: opts.capability, preferred: true, alreadyPreferred: true }));
|
|
154
|
-
return console.log(' ' + c.dim('Already shortlisted: ' + formatAddress(address) + ' for ' + opts.capability));
|
|
155
|
-
}
|
|
156
|
-
await (await contract.addPreferred(wallet, opts.capability, address)).wait();
|
|
157
|
-
if (opts.json) return console.log(JSON.stringify({ address, capability: opts.capability, preferred: true }));
|
|
158
|
-
console.log(' ' + c.success + c.white(' Shortlisted: ' + formatAddress(address) + ' for ' + opts.capability));
|
|
159
|
-
});
|
|
160
|
-
|
|
161
|
-
shortlist
|
|
162
|
-
.command("remove <address>")
|
|
163
|
-
.description("Remove a provider from your shortlist for a capability")
|
|
164
|
-
.requiredOption("--capability <name>", "Capability name")
|
|
165
|
-
.option("--json")
|
|
166
|
-
.action(async (address, opts) => {
|
|
167
|
-
const config = loadConfig();
|
|
168
|
-
if (!config.policyEngineAddress) {
|
|
169
|
-
console.error("policyEngineAddress not configured. Run `arc402 config set policyEngineAddress <address>`.");
|
|
170
|
-
process.exit(1);
|
|
171
|
-
}
|
|
172
|
-
const { signer, address: wallet } = await requireSigner(config);
|
|
173
|
-
const contract = getPolicyEngine(config.policyEngineAddress, signer);
|
|
174
|
-
const isPreferredNow = await contract.isPreferred(wallet, opts.capability, address);
|
|
175
|
-
if (!isPreferredNow) {
|
|
176
|
-
if (opts.json) return console.log(JSON.stringify({ address, capability: opts.capability, preferred: false, notPreferred: true }));
|
|
177
|
-
return console.log(' ' + c.dim('Not shortlisted: ' + formatAddress(address) + ' for ' + opts.capability));
|
|
178
|
-
}
|
|
179
|
-
await (await contract.removePreferred(wallet, opts.capability, address)).wait();
|
|
180
|
-
if (opts.json) return console.log(JSON.stringify({ address, capability: opts.capability, preferred: false }));
|
|
181
|
-
console.log(' ' + c.success + c.white(' Removed from shortlist: ' + formatAddress(address) + ' for ' + opts.capability));
|
|
182
|
-
});
|
|
183
|
-
|
|
184
|
-
shortlist
|
|
185
|
-
.command("check <address>")
|
|
186
|
-
.description("Check if an address is shortlisted for a capability")
|
|
187
|
-
.requiredOption("--capability <name>", "Capability name")
|
|
188
|
-
.option("--json")
|
|
189
|
-
.action(async (address, opts) => {
|
|
190
|
-
const config = loadConfig();
|
|
191
|
-
if (!config.policyEngineAddress) {
|
|
192
|
-
console.error("policyEngineAddress not configured.");
|
|
193
|
-
process.exit(1);
|
|
194
|
-
}
|
|
195
|
-
const { provider } = await getClient(config);
|
|
196
|
-
const { address: wallet } = await requireSigner(config);
|
|
197
|
-
const contract = getPolicyEngine(config.policyEngineAddress, provider);
|
|
198
|
-
const preferred = await contract.isPreferred(wallet, opts.capability, address);
|
|
199
|
-
if (opts.json) return console.log(JSON.stringify({ address, capability: opts.capability, preferred }));
|
|
200
|
-
if (preferred) {
|
|
201
|
-
console.log(' ' + c.success + c.white(' ' + formatAddress(address) + ' is shortlisted for ' + opts.capability));
|
|
202
|
-
} else {
|
|
203
|
-
console.log(' ' + c.warning + c.white(' ' + formatAddress(address) + ' is NOT shortlisted for ' + opts.capability));
|
|
204
|
-
}
|
|
205
|
-
});
|
|
206
|
-
|
|
207
|
-
shortlist
|
|
208
|
-
.command("list")
|
|
209
|
-
.description("List shortlisted providers, optionally filtered by capability")
|
|
210
|
-
.option("--capability <name>", "Filter by capability name")
|
|
211
|
-
.option("--from-block <n>", "Start block for event log query (default: latest-9000 to stay within public RPC limits)")
|
|
212
|
-
.option("--json")
|
|
213
|
-
.action(async (opts) => {
|
|
214
|
-
const config = loadConfig();
|
|
215
|
-
if (!config.policyEngineAddress) {
|
|
216
|
-
console.error("policyEngineAddress not configured.");
|
|
217
|
-
process.exit(1);
|
|
218
|
-
}
|
|
219
|
-
const { provider } = await getClient(config);
|
|
220
|
-
const { address: wallet } = await requireSigner(config);
|
|
221
|
-
const contract = getPolicyEngine(config.policyEngineAddress, provider);
|
|
222
|
-
|
|
223
|
-
if (opts.capability) {
|
|
224
|
-
const addresses = await contract.getPreferred(wallet, opts.capability) as string[];
|
|
225
|
-
if (opts.json) return console.log(JSON.stringify({ wallet, capability: opts.capability, preferred: addresses }, null, 2));
|
|
226
|
-
if (addresses.length === 0) return console.log(`No providers shortlisted for ${opts.capability}`);
|
|
227
|
-
addresses.forEach((a) => console.log(a));
|
|
228
|
-
return;
|
|
229
|
-
}
|
|
230
|
-
|
|
231
|
-
// No capability filter — reconstruct from events
|
|
232
|
-
const latestBlock = await provider.getBlockNumber();
|
|
233
|
-
const fromBlock = opts.fromBlock !== undefined ? parseInt(opts.fromBlock, 10) : Math.max(0, latestBlock - 9000);
|
|
234
|
-
const [preferredEvents, unpreferredEvents] = await Promise.all([
|
|
235
|
-
contract.queryFilter(contract.filters.ProviderPreferred(wallet), fromBlock),
|
|
236
|
-
contract.queryFilter(contract.filters.ProviderUnpreferred(wallet), fromBlock),
|
|
237
|
-
]);
|
|
238
|
-
const removed = new Set(
|
|
239
|
-
unpreferredEvents.map((e) => {
|
|
240
|
-
const args = (e as ethers.EventLog).args;
|
|
241
|
-
return `${(args.provider as string).toLowerCase()}::${args.capability as string}`;
|
|
242
|
-
})
|
|
243
|
-
);
|
|
244
|
-
const byCapability: Record<string, string[]> = {};
|
|
245
|
-
for (const e of preferredEvents) {
|
|
246
|
-
const args = (e as ethers.EventLog).args;
|
|
247
|
-
const addr = args.provider as string;
|
|
248
|
-
const cap = args.capability as string;
|
|
249
|
-
if (removed.has(`${addr.toLowerCase()}::${cap}`)) continue;
|
|
250
|
-
if (!byCapability[cap]) byCapability[cap] = [];
|
|
251
|
-
if (!byCapability[cap].includes(addr)) byCapability[cap].push(addr);
|
|
252
|
-
}
|
|
253
|
-
|
|
254
|
-
if (opts.json) return console.log(JSON.stringify({ wallet, shortlist: byCapability }, null, 2));
|
|
255
|
-
const caps = Object.keys(byCapability);
|
|
256
|
-
if (caps.length === 0) return console.log("No providers on your shortlist");
|
|
257
|
-
for (const cap of caps) {
|
|
258
|
-
console.log(`${cap}:`);
|
|
259
|
-
byCapability[cap].forEach((a) => console.log(` ${a}`));
|
|
260
|
-
}
|
|
261
|
-
});
|
|
262
|
-
|
|
263
|
-
export default policy;
|
package/src/commands/relay.ts
DELETED
|
@@ -1,277 +0,0 @@
|
|
|
1
|
-
import { Command } from "commander";
|
|
2
|
-
import * as fs from "fs";
|
|
3
|
-
import * as path from "path";
|
|
4
|
-
import * as os from "os";
|
|
5
|
-
import * as http from "http";
|
|
6
|
-
import * as https from "https";
|
|
7
|
-
import { spawn } from "child_process";
|
|
8
|
-
import { c } from '../ui/colors.js';
|
|
9
|
-
|
|
10
|
-
import { fileURLToPath } from "node:url";
|
|
11
|
-
const __filename = fileURLToPath(import.meta.url);
|
|
12
|
-
const __dirname = path.dirname(__filename);
|
|
13
|
-
|
|
14
|
-
const PID_FILE = path.join(os.homedir(), ".arc402", "relay.pid");
|
|
15
|
-
|
|
16
|
-
// ─── HTTP helper (no external deps) ──────────────────────────────────────────
|
|
17
|
-
|
|
18
|
-
function relayRequest(
|
|
19
|
-
relayUrl: string,
|
|
20
|
-
method: string,
|
|
21
|
-
urlPath: string,
|
|
22
|
-
body?: object
|
|
23
|
-
): Promise<{ status: number; data: unknown }> {
|
|
24
|
-
return new Promise((resolve, reject) => {
|
|
25
|
-
const parsed = new URL(urlPath, relayUrl);
|
|
26
|
-
const isHttps = parsed.protocol === "https:";
|
|
27
|
-
const mod = isHttps ? https : http;
|
|
28
|
-
const bodyStr = body ? JSON.stringify(body) : undefined;
|
|
29
|
-
const options: http.RequestOptions = {
|
|
30
|
-
hostname: parsed.hostname,
|
|
31
|
-
port: parsed.port || (isHttps ? 443 : 80),
|
|
32
|
-
path: parsed.pathname + (parsed.search || ""),
|
|
33
|
-
method,
|
|
34
|
-
headers: {
|
|
35
|
-
"Content-Type": "application/json",
|
|
36
|
-
...(bodyStr ? { "Content-Length": String(Buffer.byteLength(bodyStr)) } : {}),
|
|
37
|
-
},
|
|
38
|
-
};
|
|
39
|
-
const req = mod.request(options, (res) => {
|
|
40
|
-
let raw = "";
|
|
41
|
-
res.on("data", (c: Buffer) => { raw += c.toString(); });
|
|
42
|
-
res.on("end", () => {
|
|
43
|
-
try {
|
|
44
|
-
resolve({ status: res.statusCode ?? 0, data: JSON.parse(raw) });
|
|
45
|
-
} catch {
|
|
46
|
-
resolve({ status: res.statusCode ?? 0, data: raw });
|
|
47
|
-
}
|
|
48
|
-
});
|
|
49
|
-
});
|
|
50
|
-
req.on("error", reject);
|
|
51
|
-
if (bodyStr) req.write(bodyStr);
|
|
52
|
-
req.end();
|
|
53
|
-
});
|
|
54
|
-
}
|
|
55
|
-
|
|
56
|
-
// ─── Daemon loop (runs in-process when spawned with ARC402_RELAY_DAEMON=1) ───
|
|
57
|
-
|
|
58
|
-
async function runDaemonLoop(opts: {
|
|
59
|
-
relayUrl: string;
|
|
60
|
-
address: string;
|
|
61
|
-
pollInterval: number;
|
|
62
|
-
onMessage: string;
|
|
63
|
-
}): Promise<void> {
|
|
64
|
-
let lastSeen: string | null = null;
|
|
65
|
-
|
|
66
|
-
const poll = async () => {
|
|
67
|
-
try {
|
|
68
|
-
const qs = `?address=${encodeURIComponent(opts.address)}` +
|
|
69
|
-
(lastSeen ? `&since=${encodeURIComponent(lastSeen)}` : "");
|
|
70
|
-
const result = await relayRequest(opts.relayUrl, "GET", `/poll${qs}`);
|
|
71
|
-
const data = result.data as { messages?: Array<{ messageId: string; payload: unknown }> };
|
|
72
|
-
const messages = data.messages || [];
|
|
73
|
-
for (const msg of messages) {
|
|
74
|
-
lastSeen = msg.messageId;
|
|
75
|
-
// Spawn the handler script with message JSON on stdin
|
|
76
|
-
const child = spawn(opts.onMessage, [], {
|
|
77
|
-
stdio: ["pipe", "inherit", "inherit"],
|
|
78
|
-
shell: true,
|
|
79
|
-
});
|
|
80
|
-
child.stdin.write(JSON.stringify(msg));
|
|
81
|
-
child.stdin.end();
|
|
82
|
-
}
|
|
83
|
-
} catch {
|
|
84
|
-
// Silent retry — relay may be temporarily unreachable
|
|
85
|
-
}
|
|
86
|
-
};
|
|
87
|
-
|
|
88
|
-
// Initial poll immediately, then on interval
|
|
89
|
-
await poll();
|
|
90
|
-
setInterval(poll, opts.pollInterval);
|
|
91
|
-
|
|
92
|
-
// Keep process alive
|
|
93
|
-
process.stdin.resume();
|
|
94
|
-
}
|
|
95
|
-
|
|
96
|
-
// ─── Command registration ─────────────────────────────────────────────────────
|
|
97
|
-
|
|
98
|
-
export function registerRelayCommands(program: Command): void {
|
|
99
|
-
const relay = program
|
|
100
|
-
.command("relay")
|
|
101
|
-
.description("Send and receive messages via an ARC-402 relay (Spec 21)");
|
|
102
|
-
|
|
103
|
-
// ── relay send ──────────────────────────────────────────────────────────────
|
|
104
|
-
relay
|
|
105
|
-
.command("send")
|
|
106
|
-
.description("Send a message to an address via the relay")
|
|
107
|
-
.requiredOption("--to <address>", "Recipient address")
|
|
108
|
-
.requiredOption("--payload <json>", "JSON payload string")
|
|
109
|
-
.requiredOption("--relay <url>", "Relay server URL")
|
|
110
|
-
.option("--json", "Machine-parseable output")
|
|
111
|
-
.action(async (opts) => {
|
|
112
|
-
let payload: unknown;
|
|
113
|
-
try {
|
|
114
|
-
payload = JSON.parse(opts.payload);
|
|
115
|
-
} catch {
|
|
116
|
-
console.error("Error: --payload must be valid JSON");
|
|
117
|
-
process.exit(1);
|
|
118
|
-
}
|
|
119
|
-
|
|
120
|
-
const result = await relayRequest(opts.relay, "POST", "/send", {
|
|
121
|
-
to: opts.to,
|
|
122
|
-
payload,
|
|
123
|
-
});
|
|
124
|
-
|
|
125
|
-
if (result.status !== 200) {
|
|
126
|
-
console.error(`Relay error (${result.status}): ${JSON.stringify(result.data)}`);
|
|
127
|
-
process.exit(1);
|
|
128
|
-
}
|
|
129
|
-
|
|
130
|
-
if (opts.json) {
|
|
131
|
-
console.log(JSON.stringify(result.data));
|
|
132
|
-
} else {
|
|
133
|
-
const d = result.data as { messageId?: string };
|
|
134
|
-
console.log(' ' + c.success + c.white(' Sent — messageId: ' + d.messageId));
|
|
135
|
-
}
|
|
136
|
-
});
|
|
137
|
-
|
|
138
|
-
// ── relay poll ──────────────────────────────────────────────────────────────
|
|
139
|
-
relay
|
|
140
|
-
.command("poll")
|
|
141
|
-
.description("Poll for messages addressed to an address")
|
|
142
|
-
.requiredOption("--address <address>", "Address to poll for")
|
|
143
|
-
.requiredOption("--relay <url>", "Relay server URL")
|
|
144
|
-
.option("--since <messageId>", "Only return messages after this messageId")
|
|
145
|
-
.option("--json", "Machine-parseable output")
|
|
146
|
-
.action(async (opts) => {
|
|
147
|
-
const qs = `?address=${encodeURIComponent(opts.address)}` +
|
|
148
|
-
(opts.since ? `&since=${encodeURIComponent(opts.since)}` : "");
|
|
149
|
-
|
|
150
|
-
const result = await relayRequest(opts.relay, "GET", `/poll${qs}`);
|
|
151
|
-
|
|
152
|
-
if (result.status !== 200) {
|
|
153
|
-
console.error(`Relay error (${result.status}): ${JSON.stringify(result.data)}`);
|
|
154
|
-
process.exit(1);
|
|
155
|
-
}
|
|
156
|
-
|
|
157
|
-
const data = result.data as { messages?: unknown[] };
|
|
158
|
-
const messages = data.messages || [];
|
|
159
|
-
|
|
160
|
-
if (opts.json) {
|
|
161
|
-
console.log(JSON.stringify(data));
|
|
162
|
-
return;
|
|
163
|
-
}
|
|
164
|
-
|
|
165
|
-
if (messages.length === 0) {
|
|
166
|
-
console.log(' ' + c.dim('No messages.'));
|
|
167
|
-
return;
|
|
168
|
-
}
|
|
169
|
-
|
|
170
|
-
for (const msg of messages as Array<{ messageId: string; from: string; timestamp: number }>) {
|
|
171
|
-
const ts = new Date(msg.timestamp).toISOString();
|
|
172
|
-
console.log(`[${ts}] ${msg.messageId.slice(0, 12)}... from=${msg.from}`);
|
|
173
|
-
}
|
|
174
|
-
});
|
|
175
|
-
|
|
176
|
-
// ── relay daemon ────────────────────────────────────────────────────────────
|
|
177
|
-
const daemon = relay
|
|
178
|
-
.command("daemon")
|
|
179
|
-
.description("Persistent relay polling daemon");
|
|
180
|
-
|
|
181
|
-
daemon
|
|
182
|
-
.command("start")
|
|
183
|
-
.description("Start the relay daemon in the background")
|
|
184
|
-
.requiredOption("--relay <url>", "Relay server URL")
|
|
185
|
-
.requiredOption("--address <address>", "Address to poll for messages")
|
|
186
|
-
.requiredOption("--poll-interval <ms>", "Polling interval in milliseconds", "2000")
|
|
187
|
-
.requiredOption("--on-message <script>", "Script to invoke for each incoming message (receives JSON on stdin)")
|
|
188
|
-
.option("--json", "Machine-parseable output")
|
|
189
|
-
.action((opts) => {
|
|
190
|
-
// Check if already running
|
|
191
|
-
if (fs.existsSync(PID_FILE)) {
|
|
192
|
-
try {
|
|
193
|
-
const existingPid = parseInt(fs.readFileSync(PID_FILE, "utf8").trim(), 10);
|
|
194
|
-
process.kill(existingPid, 0); // Check if alive
|
|
195
|
-
console.error(`Daemon already running (PID ${existingPid}). Run 'arc402 relay daemon stop' first.`);
|
|
196
|
-
process.exit(1);
|
|
197
|
-
} catch {
|
|
198
|
-
// PID file is stale — clean it up
|
|
199
|
-
fs.unlinkSync(PID_FILE);
|
|
200
|
-
}
|
|
201
|
-
}
|
|
202
|
-
|
|
203
|
-
// Spawn a detached child process
|
|
204
|
-
const child = spawn(process.execPath, [__filename], {
|
|
205
|
-
detached: true,
|
|
206
|
-
stdio: "ignore",
|
|
207
|
-
env: {
|
|
208
|
-
...process.env,
|
|
209
|
-
ARC402_RELAY_DAEMON: "1",
|
|
210
|
-
ARC402_RELAY_URL: opts.relay,
|
|
211
|
-
ARC402_RELAY_ADDRESS: opts.address,
|
|
212
|
-
ARC402_RELAY_INTERVAL: opts.pollInterval,
|
|
213
|
-
ARC402_RELAY_HANDLER: opts.onMessage,
|
|
214
|
-
},
|
|
215
|
-
});
|
|
216
|
-
child.unref();
|
|
217
|
-
|
|
218
|
-
fs.mkdirSync(path.dirname(PID_FILE), { recursive: true });
|
|
219
|
-
fs.writeFileSync(PID_FILE, String(child.pid), { mode: 0o600 });
|
|
220
|
-
|
|
221
|
-
if (opts.json) {
|
|
222
|
-
console.log(JSON.stringify({ started: true, pid: child.pid, pidFile: PID_FILE }));
|
|
223
|
-
} else {
|
|
224
|
-
console.log(' ' + c.success + c.white(' Daemon started (PID ' + child.pid + ')'));
|
|
225
|
-
}
|
|
226
|
-
});
|
|
227
|
-
|
|
228
|
-
daemon
|
|
229
|
-
.command("stop")
|
|
230
|
-
.description("Stop the relay daemon")
|
|
231
|
-
.option("--json", "Machine-parseable output")
|
|
232
|
-
.action((opts) => {
|
|
233
|
-
if (!fs.existsSync(PID_FILE)) {
|
|
234
|
-
if (opts.json) {
|
|
235
|
-
console.log(JSON.stringify({ stopped: false, reason: "no pid file" }));
|
|
236
|
-
} else {
|
|
237
|
-
console.log(' ' + c.dim('No running daemon found.'));
|
|
238
|
-
}
|
|
239
|
-
return;
|
|
240
|
-
}
|
|
241
|
-
|
|
242
|
-
const pid = parseInt(fs.readFileSync(PID_FILE, "utf8").trim(), 10);
|
|
243
|
-
try {
|
|
244
|
-
process.kill(pid, "SIGTERM");
|
|
245
|
-
fs.unlinkSync(PID_FILE);
|
|
246
|
-
if (opts.json) {
|
|
247
|
-
console.log(JSON.stringify({ stopped: true, pid }));
|
|
248
|
-
} else {
|
|
249
|
-
console.log(' ' + c.success + c.white(' Daemon stopped (PID ' + pid + ')'));
|
|
250
|
-
}
|
|
251
|
-
} catch (err: unknown) {
|
|
252
|
-
const msg = err instanceof Error ? err.message : String(err);
|
|
253
|
-
if (opts.json) {
|
|
254
|
-
console.log(JSON.stringify({ stopped: false, pid, error: msg }));
|
|
255
|
-
} else {
|
|
256
|
-
console.error(`Failed to stop daemon: ${msg}`);
|
|
257
|
-
// Clean up stale PID file
|
|
258
|
-
fs.unlinkSync(PID_FILE);
|
|
259
|
-
}
|
|
260
|
-
}
|
|
261
|
-
});
|
|
262
|
-
}
|
|
263
|
-
|
|
264
|
-
// ─── Daemon entry point ───────────────────────────────────────────────────────
|
|
265
|
-
// When spawned as a background process via daemon start
|
|
266
|
-
|
|
267
|
-
if (process.env.ARC402_RELAY_DAEMON === "1") {
|
|
268
|
-
runDaemonLoop({
|
|
269
|
-
relayUrl: process.env.ARC402_RELAY_URL || "",
|
|
270
|
-
address: process.env.ARC402_RELAY_ADDRESS || "",
|
|
271
|
-
pollInterval: parseInt(process.env.ARC402_RELAY_INTERVAL || "2000", 10),
|
|
272
|
-
onMessage: process.env.ARC402_RELAY_HANDLER || "echo",
|
|
273
|
-
}).catch((err) => {
|
|
274
|
-
process.stderr.write(`Daemon error: ${err}\n`);
|
|
275
|
-
process.exit(1);
|
|
276
|
-
});
|
|
277
|
-
}
|
|
@@ -1,24 +0,0 @@
|
|
|
1
|
-
import { Command } from "commander";
|
|
2
|
-
import { ProviderResponseType, ServiceAgreementClient } from "@arc402/sdk";
|
|
3
|
-
import { loadConfig } from "../config.js";
|
|
4
|
-
import { getClient, requireSigner } from "../client.js";
|
|
5
|
-
import { hashFile, hashString } from "../utils/hash.js";
|
|
6
|
-
import { c } from '../ui/colors.js';
|
|
7
|
-
import { startSpinner } from '../ui/spinner.js';
|
|
8
|
-
|
|
9
|
-
export function registerRemediateCommands(program: Command): void {
|
|
10
|
-
const remediate = program.command("remediate").description("Negotiated remediation before formal dispute");
|
|
11
|
-
remediate.command("request <id>").requiredOption("--text <feedback>").option("--uri <uri>", "Structured feedback URI", "").option("--file <path>").option("--previous <hash>", "Previous transcript hash", "0x0000000000000000000000000000000000000000000000000000000000000000").action(async (id, opts) => {
|
|
12
|
-
const config = loadConfig(); if (!config.serviceAgreementAddress) throw new Error("serviceAgreementAddress missing in config"); const { signer } = await requireSigner(config); const client = new ServiceAgreementClient(config.serviceAgreementAddress, signer);
|
|
13
|
-
const hash = opts.file ? hashFile(opts.file) : hashString(opts.text); await client.requestRevision(BigInt(id), hash, opts.uri, opts.previous); console.log(' ' + c.success + c.white(' Revision requested — agreement #' + id));
|
|
14
|
-
});
|
|
15
|
-
remediate.command("respond <id>").requiredOption("--type <type>", "revise|defend|counter|partial-settlement|human-review|escalate").requiredOption("--text <response>").option("--uri <uri>", "Structured response URI", "").option("--file <path>").option("--previous <hash>", "Previous transcript hash", "0x0000000000000000000000000000000000000000000000000000000000000000").option("--provider-payout <amount>", "Wei/token units for partial settlement", "0").action(async (id, opts) => {
|
|
16
|
-
const config = loadConfig(); if (!config.serviceAgreementAddress) throw new Error("serviceAgreementAddress missing in config"); const { signer } = await requireSigner(config); const client = new ServiceAgreementClient(config.serviceAgreementAddress, signer);
|
|
17
|
-
const map: Record<string, ProviderResponseType> = { revise: ProviderResponseType.REVISE, defend: ProviderResponseType.DEFEND, counter: ProviderResponseType.COUNTER, 'partial-settlement': ProviderResponseType.PARTIAL_SETTLEMENT, 'human-review': ProviderResponseType.REQUEST_HUMAN_REVIEW, escalate: ProviderResponseType.ESCALATE };
|
|
18
|
-
const hash = opts.file ? hashFile(opts.file) : hashString(opts.text); await client.respondToRevision(BigInt(id), map[String(opts.type)], hash, opts.uri, opts.previous, BigInt(opts.providerPayout)); console.log(' ' + c.success + c.white(' Response recorded — agreement #' + id));
|
|
19
|
-
});
|
|
20
|
-
remediate.command("status <id>").option("--json").action(async (id, opts) => {
|
|
21
|
-
const config = loadConfig(); if (!config.serviceAgreementAddress) throw new Error("serviceAgreementAddress missing in config"); const { provider } = await getClient(config); const client = new ServiceAgreementClient(config.serviceAgreementAddress, provider);
|
|
22
|
-
const remediation = await client.getRemediationCase(BigInt(id)); const out = { remediation }; console.log(JSON.stringify(out, (_k, value) => typeof value === 'bigint' ? value.toString() : value, opts.json ? 2 : 2));
|
|
23
|
-
});
|
|
24
|
-
}
|