arc402-cli 0.7.5 → 0.8.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/MIGRATION-SPEC.md +108 -0
- package/dist/abis.js +14 -17
- 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 +27 -61
- 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 +5 -9
- package/dist/client.js.map +1 -1
- package/dist/coinbase-smart-wallet.js +1 -4
- package/dist/coinbase-smart-wallet.js.map +1 -1
- package/dist/commands/accept.js +25 -28
- package/dist/commands/accept.js.map +1 -1
- package/dist/commands/agent-handshake.js +15 -18
- package/dist/commands/agent-handshake.js.map +1 -1
- package/dist/commands/agent.js +98 -104
- package/dist/commands/agent.js.map +1 -1
- package/dist/commands/agreements.js +62 -98
- package/dist/commands/agreements.js.map +1 -1
- package/dist/commands/arbitrator.js +45 -81
- package/dist/commands/arbitrator.js.map +1 -1
- package/dist/commands/arena-handshake.js +27 -30
- package/dist/commands/arena-handshake.js.map +1 -1
- package/dist/commands/arena.js +12 -18
- package/dist/commands/arena.js.map +1 -1
- package/dist/commands/backup.js +30 -36
- package/dist/commands/backup.js.map +1 -1
- package/dist/commands/cancel.js +15 -18
- package/dist/commands/cancel.js.map +1 -1
- package/dist/commands/channel.js +45 -81
- package/dist/commands/channel.js.map +1 -1
- package/dist/commands/coldstart.js +31 -34
- package/dist/commands/coldstart.js.map +1 -1
- package/dist/commands/config.js +23 -29
- package/dist/commands/config.js.map +1 -1
- package/dist/commands/contract-interaction.js +12 -15
- package/dist/commands/contract-interaction.js.map +1 -1
- package/dist/commands/daemon.d.ts.map +1 -1
- package/dist/commands/daemon.js +98 -135
- package/dist/commands/daemon.js.map +1 -1
- package/dist/commands/deliver.js +37 -76
- package/dist/commands/deliver.js.map +1 -1
- package/dist/commands/discover.js +24 -27
- package/dist/commands/discover.js.map +1 -1
- package/dist/commands/dispute.js +104 -110
- package/dist/commands/dispute.js.map +1 -1
- package/dist/commands/doctor.js +16 -55
- package/dist/commands/doctor.js.map +1 -1
- package/dist/commands/endpoint.js +56 -95
- package/dist/commands/endpoint.js.map +1 -1
- package/dist/commands/feed.js +11 -18
- package/dist/commands/feed.js.map +1 -1
- package/dist/commands/hire.js +37 -40
- package/dist/commands/hire.js.map +1 -1
- package/dist/commands/migrate.js +30 -33
- package/dist/commands/migrate.js.map +1 -1
- package/dist/commands/negotiate.d.ts.map +1 -1
- package/dist/commands/negotiate.js +34 -36
- package/dist/commands/negotiate.js.map +1 -1
- package/dist/commands/openshell.js +68 -104
- package/dist/commands/openshell.js.map +1 -1
- package/dist/commands/owner.js +17 -20
- package/dist/commands/owner.js.map +1 -1
- package/dist/commands/policy.js +41 -43
- package/dist/commands/policy.js.map +1 -1
- package/dist/commands/relay.d.ts.map +1 -1
- package/dist/commands/relay.js +18 -51
- package/dist/commands/relay.js.map +1 -1
- package/dist/commands/remediate.js +20 -23
- package/dist/commands/remediate.js.map +1 -1
- package/dist/commands/reputation.js +25 -27
- package/dist/commands/reputation.js.map +1 -1
- package/dist/commands/setup.js +65 -104
- package/dist/commands/setup.js.map +1 -1
- package/dist/commands/trust.js +17 -20
- package/dist/commands/trust.js.map +1 -1
- package/dist/commands/verify.js +18 -21
- package/dist/commands/verify.js.map +1 -1
- package/dist/commands/wallet.js +619 -625
- package/dist/commands/wallet.js.map +1 -1
- package/dist/commands/watch.js +33 -36
- package/dist/commands/watch.js.map +1 -1
- package/dist/commands/watchtower.js +37 -73
- package/dist/commands/watchtower.js.map +1 -1
- package/dist/commands/workroom.d.ts.map +1 -1
- package/dist/commands/workroom.js +138 -171
- package/dist/commands/workroom.js.map +1 -1
- package/dist/config.js +21 -65
- package/dist/config.js.map +1 -1
- package/dist/daemon/config.d.ts.map +1 -1
- package/dist/daemon/config.js +16 -53
- package/dist/daemon/config.js.map +1 -1
- 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 +13 -47
- package/dist/daemon/hire-listener.js.map +1 -1
- package/dist/daemon/index.d.ts +1 -1
- package/dist/daemon/index.d.ts.map +1 -1
- package/dist/daemon/index.js +50 -88
- 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 +11 -51
- 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 +19 -53
- package/dist/daemon/notify.js.map +1 -1
- package/dist/daemon/token-metering.js +8 -47
- 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 +23 -27
- 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 +8 -12
- package/dist/daemon/wallet-monitor.js.map +1 -1
- package/dist/drain-v4.js +26 -64
- package/dist/drain-v4.js.map +1 -1
- package/dist/endpoint-config.js +20 -63
- package/dist/endpoint-config.js.map +1 -1
- package/dist/endpoint-notify.js +9 -48
- package/dist/endpoint-notify.js.map +1 -1
- package/dist/index.js +16 -50
- package/dist/index.js.map +1 -1
- package/dist/openshell-runtime.d.ts.map +1 -1
- package/dist/openshell-runtime.js +38 -82
- package/dist/openshell-runtime.js.map +1 -1
- package/dist/program.d.ts.map +1 -1
- package/dist/program.js +77 -83
- package/dist/program.js.map +1 -1
- package/dist/repl.js +25 -31
- package/dist/repl.js.map +1 -1
- package/dist/signing.js +3 -6
- package/dist/signing.js.map +1 -1
- package/dist/telegram-notify.js +3 -40
- package/dist/telegram-notify.js.map +1 -1
- package/dist/tui/App.d.ts +1 -9
- package/dist/tui/App.d.ts.map +1 -1
- package/dist/tui/App.js +47 -65
- package/dist/tui/App.js.map +1 -1
- package/dist/tui/Footer.js +4 -7
- package/dist/tui/Footer.js.map +1 -1
- package/dist/tui/Header.d.ts +1 -2
- package/dist/tui/Header.d.ts.map +1 -1
- package/dist/tui/Header.js +8 -14
- package/dist/tui/Header.js.map +1 -1
- package/dist/tui/InputLine.js +17 -23
- package/dist/tui/InputLine.js.map +1 -1
- package/dist/tui/Viewport.d.ts +5 -4
- package/dist/tui/Viewport.d.ts.map +1 -1
- package/dist/tui/Viewport.js +20 -13
- package/dist/tui/Viewport.js.map +1 -1
- package/dist/tui/WalletConnectPairing.d.ts +23 -0
- package/dist/tui/WalletConnectPairing.d.ts.map +1 -0
- package/dist/tui/WalletConnectPairing.js +75 -0
- package/dist/tui/WalletConnectPairing.js.map +1 -0
- package/dist/tui/index.d.ts.map +1 -1
- package/dist/tui/index.js +14 -21
- package/dist/tui/index.js.map +1 -1
- package/dist/tui/useChat.js +13 -19
- package/dist/tui/useChat.js.map +1 -1
- package/dist/tui/useCommand.d.ts +2 -7
- package/dist/tui/useCommand.d.ts.map +1 -1
- package/dist/tui/useCommand.js +77 -165
- package/dist/tui/useCommand.js.map +1 -1
- package/dist/tui/useScroll.js +9 -12
- package/dist/tui/useScroll.js.map +1 -1
- package/dist/ui/banner.js +12 -19
- package/dist/ui/banner.js.map +1 -1
- package/dist/ui/colors.js +13 -19
- package/dist/ui/colors.js.map +1 -1
- package/dist/ui/format.js +6 -14
- package/dist/ui/format.js.map +1 -1
- package/dist/ui/spinner.js +6 -12
- package/dist/ui/spinner.js.map +1 -1
- package/dist/ui/tree.js +3 -6
- package/dist/ui/tree.js.map +1 -1
- package/dist/utils/format.js +27 -41
- package/dist/utils/format.js.map +1 -1
- package/dist/utils/hash.js +4 -42
- package/dist/utils/hash.js.map +1 -1
- package/dist/utils/time.js +2 -6
- 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 +12 -19
- 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 +6 -11
- package/dist/walletconnect-session.js.map +1 -1
- package/dist/walletconnect.d.ts +6 -1
- package/dist/walletconnect.d.ts.map +1 -1
- package/dist/walletconnect.js +32 -35
- package/dist/walletconnect.js.map +1 -1
- package/package.json +7 -6
- package/src/bundler.ts +1 -1
- package/src/client.ts +1 -1
- package/src/commands/accept.ts +7 -7
- package/src/commands/agent-handshake.ts +4 -4
- package/src/commands/agent.ts +9 -9
- package/src/commands/agreements.ts +8 -8
- package/src/commands/arbitrator.ts +5 -5
- package/src/commands/arena-handshake.ts +6 -6
- package/src/commands/arena.ts +2 -2
- package/src/commands/backup.ts +1 -1
- package/src/commands/cancel.ts +6 -6
- package/src/commands/channel.ts +6 -6
- package/src/commands/coldstart.ts +5 -5
- package/src/commands/config.ts +2 -2
- package/src/commands/contract-interaction.ts +2 -2
- package/src/commands/daemon.ts +14 -11
- package/src/commands/deliver.ts +9 -9
- package/src/commands/discover.ts +5 -5
- package/src/commands/dispute.ts +7 -7
- package/src/commands/doctor.ts +2 -2
- package/src/commands/endpoint.ts +6 -6
- package/src/commands/feed.ts +1 -1
- package/src/commands/hire.ts +10 -10
- package/src/commands/migrate.ts +7 -7
- package/src/commands/negotiate.ts +6 -5
- package/src/commands/openshell.ts +4 -4
- package/src/commands/owner.ts +5 -5
- package/src/commands/policy.ts +5 -5
- package/src/commands/relay.ts +5 -1
- package/src/commands/remediate.ts +5 -5
- package/src/commands/reputation.ts +6 -6
- package/src/commands/setup.ts +1 -1
- package/src/commands/trust.ts +6 -6
- package/src/commands/verify.ts +6 -6
- package/src/commands/wallet.ts +15 -15
- package/src/commands/watch.ts +3 -3
- package/src/commands/watchtower.ts +6 -6
- package/src/commands/workroom.ts +14 -10
- package/src/daemon/config.ts +2 -1
- package/src/daemon/hire-listener.ts +3 -3
- package/src/daemon/index.ts +10 -9
- package/src/daemon/job-lifecycle.ts +1 -1
- package/src/daemon/notify.ts +4 -4
- package/src/daemon/userops.ts +4 -4
- package/src/daemon/wallet-monitor.ts +2 -2
- package/src/endpoint-notify.ts +1 -1
- package/src/index.ts +8 -7
- package/src/openshell-runtime.ts +5 -1
- package/src/program.ts +36 -36
- package/src/repl.ts +3 -3
- package/src/tui/App.tsx +26 -47
- package/src/tui/Header.tsx +3 -10
- package/src/tui/InputLine.tsx +1 -1
- package/src/tui/Viewport.tsx +22 -18
- package/src/tui/WalletConnectPairing.tsx +131 -0
- package/src/tui/index.tsx +7 -8
- package/src/tui/useChat.ts +1 -1
- package/src/tui/useCommand.ts +86 -183
- package/src/ui/banner.ts +2 -2
- package/src/ui/tree.ts +1 -1
- package/src/wallet-router.ts +2 -2
- package/src/walletconnect-session.ts +1 -1
- package/src/walletconnect.ts +20 -5
- package/tsconfig.json +16 -7
package/dist/commands/daemon.js
CHANGED
|
@@ -1,58 +1,22 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
}
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
}
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
ownKeys = Object.getOwnPropertyNames || function (o) {
|
|
21
|
-
var ar = [];
|
|
22
|
-
for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
|
|
23
|
-
return ar;
|
|
24
|
-
};
|
|
25
|
-
return ownKeys(o);
|
|
26
|
-
};
|
|
27
|
-
return function (mod) {
|
|
28
|
-
if (mod && mod.__esModule) return mod;
|
|
29
|
-
var result = {};
|
|
30
|
-
if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
|
|
31
|
-
__setModuleDefault(result, mod);
|
|
32
|
-
return result;
|
|
33
|
-
};
|
|
34
|
-
})();
|
|
35
|
-
var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
36
|
-
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
37
|
-
};
|
|
38
|
-
Object.defineProperty(exports, "__esModule", { value: true });
|
|
39
|
-
exports.registerDaemonCommands = registerDaemonCommands;
|
|
40
|
-
const fs = __importStar(require("fs"));
|
|
41
|
-
const path = __importStar(require("path"));
|
|
42
|
-
const net = __importStar(require("net"));
|
|
43
|
-
const os = __importStar(require("os"));
|
|
44
|
-
const child_process_1 = require("child_process");
|
|
45
|
-
const ethers_1 = require("ethers");
|
|
46
|
-
const prompts_1 = __importDefault(require("prompts"));
|
|
47
|
-
const config_1 = require("../config");
|
|
48
|
-
const client_1 = require("../client");
|
|
49
|
-
const spinner_1 = require("../ui/spinner");
|
|
50
|
-
const tree_1 = require("../ui/tree");
|
|
51
|
-
const colors_1 = require("../ui/colors");
|
|
52
|
-
const abis_1 = require("../abis");
|
|
53
|
-
const config_2 = require("../daemon/config");
|
|
54
|
-
const notify_1 = require("../daemon/notify");
|
|
55
|
-
const openshell_runtime_1 = require("../openshell-runtime");
|
|
1
|
+
import * as fs from "fs";
|
|
2
|
+
import * as path from "path";
|
|
3
|
+
import * as net from "net";
|
|
4
|
+
import * as os from "os";
|
|
5
|
+
import { spawn, spawnSync } from "child_process";
|
|
6
|
+
import { ethers } from "ethers";
|
|
7
|
+
import prompts from "prompts";
|
|
8
|
+
import { loadConfig } from "../config.js";
|
|
9
|
+
import { requireSigner } from "../client.js";
|
|
10
|
+
import { startSpinner } from "../ui/spinner.js";
|
|
11
|
+
import { renderTree } from "../ui/tree.js";
|
|
12
|
+
import { c } from "../ui/colors.js";
|
|
13
|
+
import { SERVICE_AGREEMENT_ABI } from "../abis.js";
|
|
14
|
+
import { DAEMON_DIR, DAEMON_PID, DAEMON_LOG, DAEMON_SOCK, DAEMON_TOML, TEMPLATE_DAEMON_TOML, loadDaemonConfig, } from "../daemon/config.js";
|
|
15
|
+
import { buildNotifier } from "../daemon/notify.js";
|
|
16
|
+
import { buildOpenShellSecretExports, buildOpenShellSshConfig, DEFAULT_RUNTIME_REMOTE_ROOT, provisionFileToSandbox, provisionRuntimeToSandbox, readOpenShellConfig, runCmd, writeOpenShellConfig, } from "../openshell-runtime.js";
|
|
17
|
+
import { fileURLToPath } from "node:url";
|
|
18
|
+
const __filename = fileURLToPath(import.meta.url);
|
|
19
|
+
const __dirname = path.dirname(__filename);
|
|
56
20
|
// ─── Constants ────────────────────────────────────────────────────────────────
|
|
57
21
|
const CHANNEL_STATES_DIR = path.join(os.homedir(), ".arc402", "channel-states");
|
|
58
22
|
// ─── Harness registry ─────────────────────────────────────────────────────────
|
|
@@ -82,7 +46,7 @@ function loadLocalState(channelId) {
|
|
|
82
46
|
* ABI-encode a ChannelState for submission to challengeChannel().
|
|
83
47
|
*/
|
|
84
48
|
function encodeChannelState(state) {
|
|
85
|
-
return
|
|
49
|
+
return ethers.AbiCoder.defaultAbiCoder().encode(["tuple(bytes32,uint256,uint256,uint256,address,uint256,bytes,bytes)"], [[
|
|
86
50
|
state.channelId,
|
|
87
51
|
BigInt(state.sequenceNumber),
|
|
88
52
|
BigInt(state.callCount),
|
|
@@ -172,12 +136,12 @@ async function runChannelWatchLoop(opts) {
|
|
|
172
136
|
process.stdin.resume();
|
|
173
137
|
}
|
|
174
138
|
function sendIpcCommand(cmd) {
|
|
175
|
-
if (!fs.existsSync(
|
|
139
|
+
if (!fs.existsSync(DAEMON_SOCK)) {
|
|
176
140
|
console.error("Daemon is not running. Launch path: run `arc402 openshell init` first, then `arc402 daemon start`.");
|
|
177
141
|
process.exit(1);
|
|
178
142
|
}
|
|
179
143
|
return new Promise((resolve, reject) => {
|
|
180
|
-
const socket = net.createConnection(
|
|
144
|
+
const socket = net.createConnection(DAEMON_SOCK, () => {
|
|
181
145
|
socket.write(JSON.stringify(cmd) + "\n");
|
|
182
146
|
});
|
|
183
147
|
let buf = "";
|
|
@@ -216,9 +180,9 @@ function sendIpcCommand(cmd) {
|
|
|
216
180
|
}
|
|
217
181
|
// ─── PID helpers ─────────────────────────────────────────────────────────────
|
|
218
182
|
function readPid() {
|
|
219
|
-
if (!fs.existsSync(
|
|
183
|
+
if (!fs.existsSync(DAEMON_PID))
|
|
220
184
|
return null;
|
|
221
|
-
const raw = fs.readFileSync(
|
|
185
|
+
const raw = fs.readFileSync(DAEMON_PID, "utf-8").trim();
|
|
222
186
|
const pid = parseInt(raw, 10);
|
|
223
187
|
return isNaN(pid) ? null : pid;
|
|
224
188
|
}
|
|
@@ -237,14 +201,14 @@ const REMOTE_DAEMON_PID = path.posix.join(REMOTE_ARC402_DIR, "daemon.pid");
|
|
|
237
201
|
const REMOTE_DAEMON_LOG = path.posix.join(REMOTE_ARC402_DIR, "daemon.log");
|
|
238
202
|
const REMOTE_DAEMON_TOML = path.posix.join(REMOTE_ARC402_DIR, "daemon.toml");
|
|
239
203
|
function syncDaemonConfigToSandbox(sandboxName) {
|
|
240
|
-
if (!fs.existsSync(
|
|
204
|
+
if (!fs.existsSync(DAEMON_TOML)) {
|
|
241
205
|
throw new Error("daemon.toml not found. Run `arc402 daemon init` first.");
|
|
242
206
|
}
|
|
243
|
-
|
|
207
|
+
provisionFileToSandbox(sandboxName, DAEMON_TOML, REMOTE_DAEMON_TOML);
|
|
244
208
|
}
|
|
245
209
|
async function readRemotePid(sandboxName) {
|
|
246
|
-
const { configPath, host } =
|
|
247
|
-
const pidRead =
|
|
210
|
+
const { configPath, host } = buildOpenShellSshConfig(sandboxName);
|
|
211
|
+
const pidRead = runCmd("ssh", [
|
|
248
212
|
"-F", configPath,
|
|
249
213
|
host,
|
|
250
214
|
`test -f ${REMOTE_DAEMON_PID} && cat ${REMOTE_DAEMON_PID}`,
|
|
@@ -268,17 +232,17 @@ async function startDaemonBackground(sandboxName, runtimeRemoteRoot) {
|
|
|
268
232
|
let child;
|
|
269
233
|
if (sandboxName) {
|
|
270
234
|
syncDaemonConfigToSandbox(sandboxName);
|
|
271
|
-
const { configPath, host } =
|
|
272
|
-
const remoteRoot = runtimeRemoteRoot ??
|
|
235
|
+
const { configPath, host } = buildOpenShellSshConfig(sandboxName);
|
|
236
|
+
const remoteRoot = runtimeRemoteRoot ?? DEFAULT_RUNTIME_REMOTE_ROOT;
|
|
273
237
|
const remoteDaemonEntry = path.posix.join(remoteRoot, "dist/daemon/index.js");
|
|
274
|
-
const secretExports =
|
|
238
|
+
const secretExports = buildOpenShellSecretExports(true);
|
|
275
239
|
const remoteCommand = [
|
|
276
240
|
`mkdir -p ${REMOTE_ARC402_DIR}`,
|
|
277
241
|
`rm -f ${REMOTE_DAEMON_PID}`,
|
|
278
242
|
secretExports,
|
|
279
243
|
`nohup env HOME=/sandbox ARC402_DAEMON_PROCESS=1 node ${remoteDaemonEntry} > /tmp/arc402-daemon-stdout.log 2> /tmp/arc402-daemon-stderr.log < /dev/null &`,
|
|
280
244
|
].filter(Boolean).join(" && ");
|
|
281
|
-
child =
|
|
245
|
+
child = spawn("ssh", [
|
|
282
246
|
"-F", configPath,
|
|
283
247
|
host,
|
|
284
248
|
remoteCommand,
|
|
@@ -294,7 +258,7 @@ async function startDaemonBackground(sandboxName, runtimeRemoteRoot) {
|
|
|
294
258
|
let telegramBotToken;
|
|
295
259
|
let telegramChatId;
|
|
296
260
|
try {
|
|
297
|
-
const config =
|
|
261
|
+
const config = loadConfig();
|
|
298
262
|
machineKey = config.privateKey;
|
|
299
263
|
telegramBotToken = config.telegramBotToken;
|
|
300
264
|
telegramChatId = config.telegramChatId;
|
|
@@ -308,7 +272,7 @@ async function startDaemonBackground(sandboxName, runtimeRemoteRoot) {
|
|
|
308
272
|
childEnv["TELEGRAM_BOT_TOKEN"] = telegramBotToken;
|
|
309
273
|
if (telegramChatId)
|
|
310
274
|
childEnv["TELEGRAM_CHAT_ID"] = telegramChatId;
|
|
311
|
-
child =
|
|
275
|
+
child = spawn(process.execPath, [daemonEntry], {
|
|
312
276
|
detached: true,
|
|
313
277
|
stdio: "ignore",
|
|
314
278
|
env: childEnv,
|
|
@@ -322,8 +286,8 @@ async function startDaemonBackground(sandboxName, runtimeRemoteRoot) {
|
|
|
322
286
|
if (sandboxName) {
|
|
323
287
|
const remotePid = await readRemotePid(sandboxName);
|
|
324
288
|
if (remotePid) {
|
|
325
|
-
console.log(` ${
|
|
326
|
-
|
|
289
|
+
console.log(` ${c.success} ARC-402 daemon started (OpenShell)`);
|
|
290
|
+
renderTree([
|
|
327
291
|
{ label: "PID", value: String(remotePid) },
|
|
328
292
|
{ label: "Log", value: REMOTE_DAEMON_LOG, last: true },
|
|
329
293
|
]);
|
|
@@ -333,10 +297,10 @@ async function startDaemonBackground(sandboxName, runtimeRemoteRoot) {
|
|
|
333
297
|
else {
|
|
334
298
|
const pid = readPid();
|
|
335
299
|
if (pid && isProcessAlive(pid)) {
|
|
336
|
-
console.log(` ${
|
|
337
|
-
|
|
300
|
+
console.log(` ${c.success} ARC-402 daemon started`);
|
|
301
|
+
renderTree([
|
|
338
302
|
{ label: "PID", value: String(pid) },
|
|
339
|
-
{ label: "Log", value:
|
|
303
|
+
{ label: "Log", value: DAEMON_LOG, last: true },
|
|
340
304
|
]);
|
|
341
305
|
return;
|
|
342
306
|
}
|
|
@@ -348,7 +312,7 @@ async function startDaemonBackground(sandboxName, runtimeRemoteRoot) {
|
|
|
348
312
|
console.error(`Expected remote log: ${REMOTE_DAEMON_LOG}`);
|
|
349
313
|
}
|
|
350
314
|
else {
|
|
351
|
-
console.error(`Check logs: ${
|
|
315
|
+
console.error(`Check logs: ${DAEMON_LOG}`);
|
|
352
316
|
}
|
|
353
317
|
process.exit(1);
|
|
354
318
|
}
|
|
@@ -359,7 +323,7 @@ async function stopDaemon(opts = {}) {
|
|
|
359
323
|
}
|
|
360
324
|
if (!isProcessAlive(pid)) {
|
|
361
325
|
// Stale PID file
|
|
362
|
-
fs.unlinkSync(
|
|
326
|
+
fs.unlinkSync(DAEMON_PID);
|
|
363
327
|
return false;
|
|
364
328
|
}
|
|
365
329
|
try {
|
|
@@ -376,8 +340,8 @@ async function stopDaemon(opts = {}) {
|
|
|
376
340
|
await new Promise((r) => setTimeout(r, 200));
|
|
377
341
|
if (!isProcessAlive(pid)) {
|
|
378
342
|
// Clean up stale PID file if daemon didn't remove it
|
|
379
|
-
if (fs.existsSync(
|
|
380
|
-
fs.unlinkSync(
|
|
343
|
+
if (fs.existsSync(DAEMON_PID))
|
|
344
|
+
fs.unlinkSync(DAEMON_PID);
|
|
381
345
|
return true;
|
|
382
346
|
}
|
|
383
347
|
}
|
|
@@ -394,9 +358,9 @@ function formatStatus(data) {
|
|
|
394
358
|
const watchtowerStatus = data.watchtower_enabled ? "active" : "disabled";
|
|
395
359
|
const bundlerStatus = `${data.bundler_mode} — ${data.bundler_endpoint || "default"}`;
|
|
396
360
|
const pending = Number(data.pending_approval ?? 0);
|
|
397
|
-
console.log(`${
|
|
361
|
+
console.log(`${c.mark} ARC-402 Daemon Status`);
|
|
398
362
|
console.log();
|
|
399
|
-
|
|
363
|
+
renderTree([
|
|
400
364
|
{ label: "State", value: String(data.state ?? "unknown") },
|
|
401
365
|
{ label: "PID", value: String(data.pid ?? "unknown") },
|
|
402
366
|
{ label: "Uptime", value: String(data.uptime ?? "unknown") },
|
|
@@ -440,7 +404,7 @@ function formatHireTable(rows) {
|
|
|
440
404
|
}
|
|
441
405
|
}
|
|
442
406
|
// ─── Command registration ─────────────────────────────────────────────────────
|
|
443
|
-
function registerDaemonCommands(program) {
|
|
407
|
+
export function registerDaemonCommands(program) {
|
|
444
408
|
const daemon = program
|
|
445
409
|
.command("daemon")
|
|
446
410
|
.description("ARC-402 daemon management and hire request workflow (Spec 32)");
|
|
@@ -453,22 +417,22 @@ function registerDaemonCommands(program) {
|
|
|
453
417
|
.action(async (opts) => {
|
|
454
418
|
const foreground = opts.foreground;
|
|
455
419
|
const forceHost = opts.host;
|
|
456
|
-
if (!fs.existsSync(
|
|
420
|
+
if (!fs.existsSync(DAEMON_TOML)) {
|
|
457
421
|
console.error("daemon.toml not found.");
|
|
458
422
|
console.error("Run `arc402 daemon init` first so the OpenShell-owned runtime has a wallet, relay, and harness configuration to boot.");
|
|
459
423
|
process.exit(1);
|
|
460
424
|
}
|
|
461
|
-
const openShellCfg = forceHost ? undefined :
|
|
425
|
+
const openShellCfg = forceHost ? undefined : readOpenShellConfig();
|
|
462
426
|
const sandboxName = openShellCfg?.sandbox.name;
|
|
463
427
|
if (forceHost) {
|
|
464
428
|
console.log("Running in host mode (--host). Sandbox bypassed.");
|
|
465
429
|
}
|
|
466
|
-
let runtimeRemoteRoot = openShellCfg?.runtime?.remote_root ??
|
|
430
|
+
let runtimeRemoteRoot = openShellCfg?.runtime?.remote_root ?? DEFAULT_RUNTIME_REMOTE_ROOT;
|
|
467
431
|
if (sandboxName) {
|
|
468
432
|
try {
|
|
469
|
-
const provisioned =
|
|
433
|
+
const provisioned = provisionRuntimeToSandbox(sandboxName, runtimeRemoteRoot);
|
|
470
434
|
runtimeRemoteRoot = provisioned.remoteRoot;
|
|
471
|
-
|
|
435
|
+
writeOpenShellConfig({
|
|
472
436
|
sandbox: openShellCfg?.sandbox ?? { name: sandboxName },
|
|
473
437
|
runtime: {
|
|
474
438
|
local_tarball: provisioned.tarballPath,
|
|
@@ -486,9 +450,9 @@ function registerDaemonCommands(program) {
|
|
|
486
450
|
if (sandboxName) {
|
|
487
451
|
syncDaemonConfigToSandbox(sandboxName);
|
|
488
452
|
const remoteDaemonEntry = path.posix.join(runtimeRemoteRoot, "dist/daemon/index.js");
|
|
489
|
-
const { configPath, host } =
|
|
490
|
-
const secretExports =
|
|
491
|
-
const result =
|
|
453
|
+
const { configPath, host } = buildOpenShellSshConfig(sandboxName);
|
|
454
|
+
const secretExports = buildOpenShellSecretExports(true);
|
|
455
|
+
const result = spawnSync("ssh", [
|
|
492
456
|
"-F", configPath,
|
|
493
457
|
host,
|
|
494
458
|
[
|
|
@@ -508,8 +472,7 @@ function registerDaemonCommands(program) {
|
|
|
508
472
|
}
|
|
509
473
|
else {
|
|
510
474
|
// Foreground mode without sandbox: import and run directly (blocking)
|
|
511
|
-
|
|
512
|
-
const { runDaemon } = require("../daemon/index");
|
|
475
|
+
const { runDaemon } = await import("../daemon/index.js");
|
|
513
476
|
await runDaemon(true);
|
|
514
477
|
}
|
|
515
478
|
return;
|
|
@@ -521,8 +484,8 @@ function registerDaemonCommands(program) {
|
|
|
521
484
|
process.exit(0);
|
|
522
485
|
}
|
|
523
486
|
// Remove stale PID file if present
|
|
524
|
-
if (fs.existsSync(
|
|
525
|
-
fs.unlinkSync(
|
|
487
|
+
if (fs.existsSync(DAEMON_PID))
|
|
488
|
+
fs.unlinkSync(DAEMON_PID);
|
|
526
489
|
if (sandboxName) {
|
|
527
490
|
console.log(`Starting ARC-402 daemon inside OpenShell sandbox: ${sandboxName}`);
|
|
528
491
|
console.log(`Using provisioned runtime: ${runtimeRemoteRoot}`);
|
|
@@ -534,16 +497,16 @@ function registerDaemonCommands(program) {
|
|
|
534
497
|
.command("stop")
|
|
535
498
|
.description("Gracefully stop the running daemon (SIGTERM + wait for exit).")
|
|
536
499
|
.action(async () => {
|
|
537
|
-
const openShellCfg =
|
|
500
|
+
const openShellCfg = readOpenShellConfig();
|
|
538
501
|
if (openShellCfg?.sandbox.name) {
|
|
539
502
|
const remotePid = await readRemotePid(openShellCfg.sandbox.name);
|
|
540
503
|
if (!remotePid) {
|
|
541
504
|
console.log("Daemon is not running.");
|
|
542
505
|
process.exit(0);
|
|
543
506
|
}
|
|
544
|
-
const { configPath, host } =
|
|
545
|
-
const stopSpinnerRemote =
|
|
546
|
-
|
|
507
|
+
const { configPath, host } = buildOpenShellSshConfig(openShellCfg.sandbox.name);
|
|
508
|
+
const stopSpinnerRemote = startSpinner(`Stopping daemon (OpenShell PID ${remotePid})...`);
|
|
509
|
+
runCmd("ssh", ["-F", configPath, host, `kill ${remotePid}`], { timeout: 20000 });
|
|
547
510
|
stopSpinnerRemote.succeed("Stop signal sent");
|
|
548
511
|
return;
|
|
549
512
|
}
|
|
@@ -552,7 +515,7 @@ function registerDaemonCommands(program) {
|
|
|
552
515
|
console.log("Daemon is not running.");
|
|
553
516
|
process.exit(0);
|
|
554
517
|
}
|
|
555
|
-
const stopSpinner =
|
|
518
|
+
const stopSpinner = startSpinner(`Stopping daemon (PID ${pid})...`);
|
|
556
519
|
const stopped = await stopDaemon({ wait: true });
|
|
557
520
|
if (stopped) {
|
|
558
521
|
stopSpinner.succeed("Daemon stopped");
|
|
@@ -580,15 +543,15 @@ function registerDaemonCommands(program) {
|
|
|
580
543
|
}
|
|
581
544
|
else {
|
|
582
545
|
console.log("Daemon was not running.");
|
|
583
|
-
if (fs.existsSync(
|
|
584
|
-
fs.unlinkSync(
|
|
546
|
+
if (fs.existsSync(DAEMON_PID))
|
|
547
|
+
fs.unlinkSync(DAEMON_PID);
|
|
585
548
|
}
|
|
586
|
-
const openShellCfg =
|
|
587
|
-
let runtimeRemoteRoot = openShellCfg?.runtime?.remote_root ??
|
|
549
|
+
const openShellCfg = readOpenShellConfig();
|
|
550
|
+
let runtimeRemoteRoot = openShellCfg?.runtime?.remote_root ?? DEFAULT_RUNTIME_REMOTE_ROOT;
|
|
588
551
|
if (openShellCfg?.sandbox.name) {
|
|
589
|
-
const provisioned =
|
|
552
|
+
const provisioned = provisionRuntimeToSandbox(openShellCfg.sandbox.name, runtimeRemoteRoot);
|
|
590
553
|
runtimeRemoteRoot = provisioned.remoteRoot;
|
|
591
|
-
|
|
554
|
+
writeOpenShellConfig({
|
|
592
555
|
sandbox: openShellCfg.sandbox,
|
|
593
556
|
runtime: {
|
|
594
557
|
local_tarball: provisioned.tarballPath,
|
|
@@ -604,7 +567,7 @@ function registerDaemonCommands(program) {
|
|
|
604
567
|
.command("status")
|
|
605
568
|
.description("Show current daemon status via IPC.")
|
|
606
569
|
.action(async () => {
|
|
607
|
-
const openShellCfg =
|
|
570
|
+
const openShellCfg = readOpenShellConfig();
|
|
608
571
|
if (openShellCfg?.sandbox.name) {
|
|
609
572
|
const remotePid = await readRemotePid(openShellCfg.sandbox.name);
|
|
610
573
|
if (!remotePid) {
|
|
@@ -612,13 +575,13 @@ function registerDaemonCommands(program) {
|
|
|
612
575
|
console.log("Launch path: arc402 openshell init, then arc402 daemon start");
|
|
613
576
|
process.exit(1);
|
|
614
577
|
}
|
|
615
|
-
console.log(`${
|
|
578
|
+
console.log(`${c.mark} ARC-402 Daemon Status`);
|
|
616
579
|
console.log();
|
|
617
|
-
|
|
580
|
+
renderTree([
|
|
618
581
|
{ label: "State", value: "running (OpenShell sandbox)" },
|
|
619
582
|
{ label: "PID", value: String(remotePid) },
|
|
620
583
|
{ label: "Sandbox", value: openShellCfg.sandbox.name },
|
|
621
|
-
{ label: "Runtime", value: openShellCfg.runtime?.remote_root ??
|
|
584
|
+
{ label: "Runtime", value: openShellCfg.runtime?.remote_root ?? DEFAULT_RUNTIME_REMOTE_ROOT },
|
|
622
585
|
{ label: "Log", value: REMOTE_DAEMON_LOG, last: true },
|
|
623
586
|
]);
|
|
624
587
|
return;
|
|
@@ -646,13 +609,13 @@ function registerDaemonCommands(program) {
|
|
|
646
609
|
.action((opts) => {
|
|
647
610
|
const follow = opts.follow;
|
|
648
611
|
const lines = parseInt(opts.lines, 10) || 50;
|
|
649
|
-
const openShellCfg =
|
|
612
|
+
const openShellCfg = readOpenShellConfig();
|
|
650
613
|
if (openShellCfg?.sandbox.name) {
|
|
651
|
-
const { configPath, host } =
|
|
614
|
+
const { configPath, host } = buildOpenShellSshConfig(openShellCfg.sandbox.name);
|
|
652
615
|
const baseCmd = follow
|
|
653
616
|
? `test -f ${REMOTE_DAEMON_LOG} && tail -f -n ${lines} ${REMOTE_DAEMON_LOG}`
|
|
654
617
|
: `test -f ${REMOTE_DAEMON_LOG} && tail -n ${lines} ${REMOTE_DAEMON_LOG}`;
|
|
655
|
-
const result =
|
|
618
|
+
const result = spawn("ssh", ["-F", configPath, host, baseCmd], { stdio: "inherit" });
|
|
656
619
|
result.on("error", (err) => {
|
|
657
620
|
console.error(`Failed to read remote log: ${err.message}`);
|
|
658
621
|
process.exit(1);
|
|
@@ -665,14 +628,14 @@ function registerDaemonCommands(program) {
|
|
|
665
628
|
}
|
|
666
629
|
return;
|
|
667
630
|
}
|
|
668
|
-
if (!fs.existsSync(
|
|
669
|
-
console.log(`Log file not found: ${
|
|
631
|
+
if (!fs.existsSync(DAEMON_LOG)) {
|
|
632
|
+
console.log(`Log file not found: ${DAEMON_LOG}`);
|
|
670
633
|
console.log("Has the OpenShell-owned runtime been started? Run `arc402 openshell init` first if needed, then `arc402 daemon start`.");
|
|
671
634
|
process.exit(0);
|
|
672
635
|
}
|
|
673
636
|
if (follow) {
|
|
674
637
|
// Stream with tail -f equivalent using spawn
|
|
675
|
-
const tail =
|
|
638
|
+
const tail = spawn("tail", ["-f", "-n", String(lines), DAEMON_LOG], {
|
|
676
639
|
stdio: "inherit",
|
|
677
640
|
});
|
|
678
641
|
tail.on("error", (err) => {
|
|
@@ -686,7 +649,7 @@ function registerDaemonCommands(program) {
|
|
|
686
649
|
}
|
|
687
650
|
else {
|
|
688
651
|
// Read last N lines
|
|
689
|
-
const content = fs.readFileSync(
|
|
652
|
+
const content = fs.readFileSync(DAEMON_LOG, "utf-8");
|
|
690
653
|
const allLines = content.split("\n").filter((l) => l.trim());
|
|
691
654
|
const slice = allLines.slice(-lines);
|
|
692
655
|
for (const line of slice) {
|
|
@@ -795,8 +758,8 @@ function registerDaemonCommands(program) {
|
|
|
795
758
|
.action(async (opts) => {
|
|
796
759
|
const force = opts.force;
|
|
797
760
|
const reconfigureHarness = opts.reconfigureHarness;
|
|
798
|
-
if (fs.existsSync(
|
|
799
|
-
console.log(`daemon.toml already exists at ${
|
|
761
|
+
if (fs.existsSync(DAEMON_TOML) && !force && !reconfigureHarness) {
|
|
762
|
+
console.log(`daemon.toml already exists at ${DAEMON_TOML}`);
|
|
800
763
|
console.log("Use --force to overwrite, or --reconfigure-harness to update the harness only.");
|
|
801
764
|
process.exit(0);
|
|
802
765
|
}
|
|
@@ -809,7 +772,7 @@ function registerDaemonCommands(program) {
|
|
|
809
772
|
console.log(" 4. opencode (OpenCode)");
|
|
810
773
|
console.log(" 5. custom (enter your own exec_command)");
|
|
811
774
|
console.log();
|
|
812
|
-
const harnessResponse = await (
|
|
775
|
+
const harnessResponse = await prompts({
|
|
813
776
|
type: "select",
|
|
814
777
|
name: "harness",
|
|
815
778
|
message: "Select harness",
|
|
@@ -825,7 +788,7 @@ function registerDaemonCommands(program) {
|
|
|
825
788
|
const selectedHarness = harnessResponse.harness ?? "openclaw";
|
|
826
789
|
let execCommand = HARNESS_REGISTRY[selectedHarness] ?? "";
|
|
827
790
|
if (selectedHarness === "custom") {
|
|
828
|
-
const customResponse = await (
|
|
791
|
+
const customResponse = await prompts({
|
|
829
792
|
type: "text",
|
|
830
793
|
name: "exec_command",
|
|
831
794
|
message: "Enter your exec_command (use {task} as placeholder)",
|
|
@@ -845,23 +808,23 @@ function registerDaemonCommands(program) {
|
|
|
845
808
|
: [`# To change harness later: arc402 daemon init --reconfigure-harness`]),
|
|
846
809
|
"",
|
|
847
810
|
].join("\n");
|
|
848
|
-
if (reconfigureHarness && fs.existsSync(
|
|
849
|
-
let existing = fs.readFileSync(
|
|
811
|
+
if (reconfigureHarness && fs.existsSync(DAEMON_TOML)) {
|
|
812
|
+
let existing = fs.readFileSync(DAEMON_TOML, "utf-8");
|
|
850
813
|
if (!/^\[work\]/m.test(existing)) {
|
|
851
814
|
console.error("[work] section not found in daemon.toml. Run: arc402 daemon init --force");
|
|
852
815
|
process.exit(1);
|
|
853
816
|
}
|
|
854
817
|
existing = existing.replace(/\[work\][\s\S]*$/, workSection);
|
|
855
|
-
fs.writeFileSync(
|
|
818
|
+
fs.writeFileSync(DAEMON_TOML, existing, { mode: 0o600 });
|
|
856
819
|
console.log(`\nHarness updated: ${selectedHarness}`);
|
|
857
820
|
console.log(`exec_command: ${execCommand}`);
|
|
858
821
|
return;
|
|
859
822
|
}
|
|
860
823
|
// ── Write full daemon.toml ────────────────────────────────────────────────
|
|
861
|
-
const toml =
|
|
862
|
-
fs.mkdirSync(
|
|
863
|
-
fs.writeFileSync(
|
|
864
|
-
console.log(`\nCreated ${
|
|
824
|
+
const toml = TEMPLATE_DAEMON_TOML.replace(/\[work\][\s\S]*$/, workSection);
|
|
825
|
+
fs.mkdirSync(DAEMON_DIR, { recursive: true, mode: 0o700 });
|
|
826
|
+
fs.writeFileSync(DAEMON_TOML, toml, { mode: 0o600 });
|
|
827
|
+
console.log(`\nCreated ${DAEMON_TOML}`);
|
|
865
828
|
console.log(`Harness: ${selectedHarness}${selectedHarness !== "custom" ? ` (${execCommand})` : ""}`);
|
|
866
829
|
console.log();
|
|
867
830
|
console.log("Next steps:");
|
|
@@ -879,11 +842,11 @@ function registerDaemonCommands(program) {
|
|
|
879
842
|
.command("show")
|
|
880
843
|
.description("Show all configured notification channels")
|
|
881
844
|
.action(() => {
|
|
882
|
-
if (!fs.existsSync(
|
|
845
|
+
if (!fs.existsSync(DAEMON_TOML)) {
|
|
883
846
|
console.error("daemon.toml not found. Run `arc402 daemon init` first.");
|
|
884
847
|
process.exit(1);
|
|
885
848
|
}
|
|
886
|
-
const cfg =
|
|
849
|
+
const cfg = loadDaemonConfig();
|
|
887
850
|
const notif = cfg.notifications;
|
|
888
851
|
const channels = [];
|
|
889
852
|
if (notif.telegram_bot_token && notif.telegram_chat_id) {
|
|
@@ -913,12 +876,12 @@ function registerDaemonCommands(program) {
|
|
|
913
876
|
.command("test")
|
|
914
877
|
.description("Send a test message to all configured channels")
|
|
915
878
|
.action(async () => {
|
|
916
|
-
if (!fs.existsSync(
|
|
879
|
+
if (!fs.existsSync(DAEMON_TOML)) {
|
|
917
880
|
console.error("daemon.toml not found. Run `arc402 daemon init` first.");
|
|
918
881
|
process.exit(1);
|
|
919
882
|
}
|
|
920
|
-
const cfg =
|
|
921
|
-
const notifier =
|
|
883
|
+
const cfg = loadDaemonConfig();
|
|
884
|
+
const notifier = buildNotifier(cfg);
|
|
922
885
|
if (!notifier.isEnabled()) {
|
|
923
886
|
console.log("No notification channels configured. Nothing to test.");
|
|
924
887
|
process.exit(0);
|
|
@@ -947,13 +910,13 @@ function registerDaemonCommands(program) {
|
|
|
947
910
|
.option("--poll-interval <ms>", "Polling interval in milliseconds", "30000")
|
|
948
911
|
.option("--json", "Machine-parseable output (one JSON object per line)")
|
|
949
912
|
.action(async (opts) => {
|
|
950
|
-
const config =
|
|
913
|
+
const config = loadConfig();
|
|
951
914
|
if (!config.serviceAgreementAddress) {
|
|
952
915
|
console.error("serviceAgreementAddress missing in config. Run `arc402 config init`.");
|
|
953
916
|
process.exit(1);
|
|
954
917
|
}
|
|
955
|
-
const { signer, address } = await
|
|
956
|
-
const contract = new
|
|
918
|
+
const { signer, address } = await requireSigner(config);
|
|
919
|
+
const contract = new ethers.Contract(config.serviceAgreementAddress, SERVICE_AGREEMENT_ABI, signer);
|
|
957
920
|
await runChannelWatchLoop({
|
|
958
921
|
pollInterval: parseInt(opts.pollInterval, 10),
|
|
959
922
|
wallet: address,
|