arc402-cli 1.0.0-rc.1 → 1.0.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 +29 -1
- package/dist/abis.js.map +1 -1
- package/dist/commands/backup.d.ts +3 -0
- package/dist/commands/backup.d.ts.map +1 -0
- package/dist/commands/backup.js +106 -0
- package/dist/commands/backup.js.map +1 -0
- 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.d.ts.map +1 -1
- package/dist/commands/config.js +11 -1
- package/dist/commands/config.js.map +1 -1
- package/dist/commands/daemon.d.ts.map +1 -1
- package/dist/commands/daemon.js +67 -0
- package/dist/commands/daemon.js.map +1 -1
- package/dist/commands/discover.d.ts.map +1 -1
- package/dist/commands/discover.js +60 -15
- package/dist/commands/discover.js.map +1 -1
- package/dist/commands/doctor.d.ts +3 -0
- package/dist/commands/doctor.d.ts.map +1 -0
- package/dist/commands/doctor.js +205 -0
- package/dist/commands/doctor.js.map +1 -0
- package/dist/commands/wallet.d.ts.map +1 -1
- package/dist/commands/wallet.js +299 -65
- package/dist/commands/wallet.js.map +1 -1
- package/dist/commands/watch.d.ts.map +1 -1
- package/dist/commands/watch.js +146 -9
- package/dist/commands/watch.js.map +1 -1
- package/dist/commands/workroom.d.ts.map +1 -1
- package/dist/commands/workroom.js +112 -6
- package/dist/commands/workroom.js.map +1 -1
- package/dist/config.d.ts +12 -0
- package/dist/config.d.ts.map +1 -1
- package/dist/config.js +41 -4
- 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 +33 -1
- package/dist/daemon/config.d.ts.map +1 -1
- package/dist/daemon/config.js +69 -0
- 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/index.d.ts +1 -0
- package/dist/daemon/index.d.ts.map +1 -1
- package/dist/daemon/index.js +793 -227
- package/dist/daemon/index.js.map +1 -1
- package/dist/daemon/notify.d.ts +35 -6
- package/dist/daemon/notify.d.ts.map +1 -1
- package/dist/daemon/notify.js +176 -48
- package/dist/daemon/notify.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 +2 -2
- package/dist/drain-v4.js.map +1 -1
- package/dist/endpoint-notify.d.ts +9 -1
- package/dist/endpoint-notify.d.ts.map +1 -1
- package/dist/endpoint-notify.js +116 -3
- package/dist/endpoint-notify.js.map +1 -1
- package/dist/index.js +81 -1
- package/dist/index.js.map +1 -1
- package/dist/program.d.ts.map +1 -1
- package/dist/program.js +6 -0
- package/dist/program.js.map +1 -1
- package/dist/repl.d.ts.map +1 -1
- package/dist/repl.js +69 -486
- package/dist/repl.js.map +1 -1
- package/dist/tui/App.d.ts +12 -0
- package/dist/tui/App.d.ts.map +1 -0
- package/dist/tui/App.js +154 -0
- package/dist/tui/App.js.map +1 -0
- package/dist/tui/Footer.d.ts +11 -0
- package/dist/tui/Footer.d.ts.map +1 -0
- package/dist/tui/Footer.js +13 -0
- package/dist/tui/Footer.js.map +1 -0
- package/dist/tui/Header.d.ts +14 -0
- package/dist/tui/Header.d.ts.map +1 -0
- package/dist/tui/Header.js +19 -0
- package/dist/tui/Header.js.map +1 -0
- package/dist/tui/InputLine.d.ts +11 -0
- package/dist/tui/InputLine.d.ts.map +1 -0
- package/dist/tui/InputLine.js +145 -0
- package/dist/tui/InputLine.js.map +1 -0
- package/dist/tui/Viewport.d.ts +14 -0
- package/dist/tui/Viewport.d.ts.map +1 -0
- package/dist/tui/Viewport.js +48 -0
- package/dist/tui/Viewport.js.map +1 -0
- package/dist/tui/WalletConnectPairing.d.ts +23 -0
- package/dist/tui/WalletConnectPairing.d.ts.map +1 -0
- package/dist/tui/WalletConnectPairing.js +61 -0
- package/dist/tui/WalletConnectPairing.js.map +1 -0
- package/dist/tui/components/Button.d.ts +7 -0
- package/dist/tui/components/Button.d.ts.map +1 -0
- package/dist/tui/components/Button.js +21 -0
- package/dist/tui/components/Button.js.map +1 -0
- package/dist/tui/components/CeremonyView.d.ts +13 -0
- package/dist/tui/components/CeremonyView.d.ts.map +1 -0
- package/dist/tui/components/CeremonyView.js +10 -0
- package/dist/tui/components/CeremonyView.js.map +1 -0
- package/dist/tui/components/CompletionDropdown.d.ts +7 -0
- package/dist/tui/components/CompletionDropdown.d.ts.map +1 -0
- package/dist/tui/components/CompletionDropdown.js +23 -0
- package/dist/tui/components/CompletionDropdown.js.map +1 -0
- package/dist/tui/components/ConfirmPrompt.d.ts +9 -0
- package/dist/tui/components/ConfirmPrompt.d.ts.map +1 -0
- package/dist/tui/components/ConfirmPrompt.js +10 -0
- package/dist/tui/components/ConfirmPrompt.js.map +1 -0
- package/dist/tui/components/CustomTextInput.d.ts +15 -0
- package/dist/tui/components/CustomTextInput.d.ts.map +1 -0
- package/dist/tui/components/CustomTextInput.js +99 -0
- package/dist/tui/components/CustomTextInput.js.map +1 -0
- package/dist/tui/components/InteractiveTable.d.ts +14 -0
- package/dist/tui/components/InteractiveTable.d.ts.map +1 -0
- package/dist/tui/components/InteractiveTable.js +61 -0
- package/dist/tui/components/InteractiveTable.js.map +1 -0
- package/dist/tui/components/StepSpinner.d.ts +11 -0
- package/dist/tui/components/StepSpinner.d.ts.map +1 -0
- package/dist/tui/components/StepSpinner.js +32 -0
- package/dist/tui/components/StepSpinner.js.map +1 -0
- package/dist/tui/components/Toast.d.ts +18 -0
- package/dist/tui/components/Toast.d.ts.map +1 -0
- package/dist/tui/components/Toast.js +29 -0
- package/dist/tui/components/Toast.js.map +1 -0
- package/dist/tui/index.d.ts +2 -0
- package/dist/tui/index.d.ts.map +1 -0
- package/dist/tui/index.js +55 -0
- package/dist/tui/index.js.map +1 -0
- package/dist/tui/useChat.d.ts +11 -0
- package/dist/tui/useChat.d.ts.map +1 -0
- package/dist/tui/useChat.js +91 -0
- package/dist/tui/useChat.js.map +1 -0
- package/dist/tui/useCommand.d.ts +12 -0
- package/dist/tui/useCommand.d.ts.map +1 -0
- package/dist/tui/useCommand.js +137 -0
- package/dist/tui/useCommand.js.map +1 -0
- package/dist/tui/useNotifications.d.ts +9 -0
- package/dist/tui/useNotifications.d.ts.map +1 -0
- package/dist/tui/useNotifications.js +17 -0
- package/dist/tui/useNotifications.js.map +1 -0
- package/dist/tui/useScroll.d.ts +17 -0
- package/dist/tui/useScroll.d.ts.map +1 -0
- package/dist/tui/useScroll.js +46 -0
- package/dist/tui/useScroll.js.map +1 -0
- package/dist/ui/format.d.ts.map +1 -1
- package/dist/ui/format.js +2 -0
- package/dist/ui/format.js.map +1 -1
- package/dist/ui/qr-render.d.ts +25 -0
- package/dist/ui/qr-render.d.ts.map +1 -0
- package/dist/ui/qr-render.js +90 -0
- package/dist/ui/qr-render.js.map +1 -0
- package/dist/ui/rpc-fallback.d.ts +11 -0
- package/dist/ui/rpc-fallback.d.ts.map +1 -0
- package/dist/ui/rpc-fallback.js +58 -0
- package/dist/ui/rpc-fallback.js.map +1 -0
- package/dist/walletconnect.d.ts +4 -0
- package/dist/walletconnect.d.ts.map +1 -1
- package/dist/walletconnect.js.map +1 -1
- package/package.json +10 -2
- 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 -257
- package/src/commands/arena.ts +0 -122
- 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 -58
- package/src/commands/contract-interaction.ts +0 -166
- package/src/commands/daemon.ts +0 -978
- package/src/commands/deliver.ts +0 -148
- package/src/commands/discover.ts +0 -297
- package/src/commands/dispute.ts +0 -375
- 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 -271
- 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 -273
- 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 -3280
- package/src/commands/watch.ts +0 -23
- package/src/commands/watchtower.ts +0 -248
- package/src/commands/workroom.ts +0 -959
- package/src/config.ts +0 -174
- package/src/daemon/config.ts +0 -308
- package/src/daemon/hire-listener.ts +0 -226
- package/src/daemon/index.ts +0 -955
- package/src/daemon/job-lifecycle.ts +0 -215
- package/src/daemon/notify.ts +0 -157
- 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 -46
- package/src/index.ts +0 -26
- package/src/openshell-runtime.ts +0 -277
- package/src/program.ts +0 -83
- package/src/repl.ts +0 -680
- package/src/signing.ts +0 -28
- package/src/telegram-notify.ts +0 -88
- package/src/ui/banner.ts +0 -51
- package/src/ui/colors.ts +0 -30
- package/src/ui/format.ts +0 -77
- 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 -294
- package/test/time.test.js +0 -11
- package/tsconfig.json +0 -19
package/dist/repl.js
CHANGED
|
@@ -8,17 +8,11 @@ const chalk_1 = __importDefault(require("chalk"));
|
|
|
8
8
|
const fs_1 = __importDefault(require("fs"));
|
|
9
9
|
const path_1 = __importDefault(require("path"));
|
|
10
10
|
const os_1 = __importDefault(require("os"));
|
|
11
|
+
const readline_1 = __importDefault(require("readline"));
|
|
11
12
|
const program_1 = require("./program");
|
|
12
13
|
const banner_1 = require("./ui/banner");
|
|
13
14
|
const colors_1 = require("./ui/colors");
|
|
14
|
-
// ───
|
|
15
|
-
class REPLExitSignal extends Error {
|
|
16
|
-
constructor(code = 0) {
|
|
17
|
-
super("repl-exit-signal");
|
|
18
|
-
this.code = code;
|
|
19
|
-
}
|
|
20
|
-
}
|
|
21
|
-
// ─── Config / banner helpers ──────────────────────────────────────────────────
|
|
15
|
+
// ─── Config helpers ────────────────────────────────────────────────────────────
|
|
22
16
|
const CONFIG_PATH = path_1.default.join(os_1.default.homedir(), ".arc402", "config.json");
|
|
23
17
|
async function loadBannerConfig() {
|
|
24
18
|
if (!fs_1.default.existsSync(CONFIG_PATH))
|
|
@@ -30,66 +24,42 @@ async function loadBannerConfig() {
|
|
|
30
24
|
const w = raw.walletContractAddress;
|
|
31
25
|
cfg.wallet = `${w.slice(0, 6)}...${w.slice(-4)}`;
|
|
32
26
|
}
|
|
33
|
-
if (raw.rpcUrl && raw.walletContractAddress) {
|
|
34
|
-
try {
|
|
35
|
-
// eslint-disable-next-line @typescript-eslint/no-var-requires
|
|
36
|
-
const ethersLib = require("ethers");
|
|
37
|
-
const provider = new ethersLib.ethers.JsonRpcProvider(raw.rpcUrl);
|
|
38
|
-
const bal = await Promise.race([
|
|
39
|
-
provider.getBalance(raw.walletContractAddress),
|
|
40
|
-
new Promise((_, r) => setTimeout(() => r(new Error("timeout")), 2000)),
|
|
41
|
-
]);
|
|
42
|
-
cfg.balance = `${parseFloat(ethersLib.ethers.formatEther(bal)).toFixed(4)} ETH`;
|
|
43
|
-
}
|
|
44
|
-
catch {
|
|
45
|
-
/* skip balance on timeout */
|
|
46
|
-
}
|
|
47
|
-
}
|
|
48
27
|
return cfg;
|
|
49
28
|
}
|
|
50
29
|
catch {
|
|
51
30
|
return undefined;
|
|
52
31
|
}
|
|
53
32
|
}
|
|
54
|
-
// ───
|
|
55
|
-
const
|
|
56
|
-
const ansi = {
|
|
57
|
-
clearScreen: `${ESC}[2J`,
|
|
58
|
-
home: `${ESC}[H`,
|
|
59
|
-
clearLine: `${ESC}[2K`,
|
|
60
|
-
clearToEol: `${ESC}[K`,
|
|
61
|
-
hideCursor: `${ESC}[?25l`,
|
|
62
|
-
showCursor: `${ESC}[?25h`,
|
|
63
|
-
move: (r, col) => `${ESC}[${r};${col}H`,
|
|
64
|
-
scrollRegion: (top, bot) => `${ESC}[${top};${bot}r`,
|
|
65
|
-
resetScroll: `${ESC}[r`,
|
|
66
|
-
};
|
|
67
|
-
function write(s) {
|
|
68
|
-
process.stdout.write(s);
|
|
69
|
-
}
|
|
70
|
-
// ─── Prompt constants ─────────────────────────────────────────────────────────
|
|
71
|
-
const PROMPT_TEXT = chalk_1.default.cyanBright("◈") +
|
|
33
|
+
// ─── Prompt ────────────────────────────────────────────────────────────────────
|
|
34
|
+
const PROMPT = chalk_1.default.cyanBright("◈") +
|
|
72
35
|
" " +
|
|
73
36
|
chalk_1.default.dim("arc402") +
|
|
74
37
|
" " +
|
|
75
38
|
chalk_1.default.white(">") +
|
|
76
39
|
" ";
|
|
77
|
-
// Visible character count of "◈ arc402 > "
|
|
78
|
-
const PROMPT_VIS = 11;
|
|
79
|
-
// ─── Known command detection ──────────────────────────────────────────────────
|
|
80
|
-
const BUILTIN_CMDS = ["help", "exit", "quit", "clear", "status"];
|
|
81
40
|
// ─── Shell-style tokenizer ────────────────────────────────────────────────────
|
|
82
41
|
function parseTokens(input) {
|
|
83
42
|
const tokens = [];
|
|
84
43
|
let current = "";
|
|
85
44
|
let inQuote = false;
|
|
86
45
|
let quoteChar = "";
|
|
46
|
+
let escape = false;
|
|
87
47
|
for (const ch of input) {
|
|
48
|
+
if (escape) {
|
|
49
|
+
current += ch;
|
|
50
|
+
escape = false;
|
|
51
|
+
continue;
|
|
52
|
+
}
|
|
88
53
|
if (inQuote) {
|
|
89
|
-
if (ch ===
|
|
54
|
+
if (quoteChar === '"' && ch === "\\") {
|
|
55
|
+
escape = true;
|
|
56
|
+
}
|
|
57
|
+
else if (ch === quoteChar) {
|
|
90
58
|
inQuote = false;
|
|
91
|
-
|
|
59
|
+
}
|
|
60
|
+
else {
|
|
92
61
|
current += ch;
|
|
62
|
+
}
|
|
93
63
|
}
|
|
94
64
|
else if (ch === '"' || ch === "'") {
|
|
95
65
|
inQuote = true;
|
|
@@ -109,468 +79,81 @@ function parseTokens(input) {
|
|
|
109
79
|
tokens.push(current);
|
|
110
80
|
return tokens;
|
|
111
81
|
}
|
|
112
|
-
// ───
|
|
113
|
-
function
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
return allTop.filter((cmd) => cmd.startsWith(trimmed));
|
|
119
|
-
}
|
|
120
|
-
const parent = trimmed.slice(0, spaceIdx);
|
|
121
|
-
const rest = trimmed.slice(spaceIdx + 1);
|
|
122
|
-
const subs = subCmds.get(parent) ?? [];
|
|
123
|
-
return subs.filter((s) => s.startsWith(rest)).map((s) => `${parent} ${s}`);
|
|
124
|
-
}
|
|
125
|
-
// ─── TUI class ────────────────────────────────────────────────────────────────
|
|
126
|
-
class TUI {
|
|
127
|
-
constructor() {
|
|
128
|
-
this.inputBuffer = "";
|
|
129
|
-
this.cursorPos = 0;
|
|
130
|
-
this.history = [];
|
|
131
|
-
this.historyIdx = -1;
|
|
132
|
-
this.historyTemp = "";
|
|
133
|
-
this.bannerLines = [];
|
|
134
|
-
this.topCmds = [];
|
|
135
|
-
this.subCmds = new Map();
|
|
136
|
-
this.commandRunning = false;
|
|
137
|
-
// ── Key handler ──────────────────────────────────────────────────────────────
|
|
138
|
-
this.boundKeyHandler = (key) => {
|
|
139
|
-
if (this.commandRunning)
|
|
140
|
-
return;
|
|
141
|
-
this.handleKey(key);
|
|
142
|
-
};
|
|
143
|
-
}
|
|
144
|
-
get termRows() {
|
|
145
|
-
return process.stdout.rows || 24;
|
|
146
|
-
}
|
|
147
|
-
get termCols() {
|
|
148
|
-
return process.stdout.columns || 80;
|
|
149
|
-
}
|
|
150
|
-
get scrollTop() {
|
|
151
|
-
// +1 for separator row after banner
|
|
152
|
-
return this.bannerLines.length + 2;
|
|
153
|
-
}
|
|
154
|
-
get scrollBot() {
|
|
155
|
-
return this.termRows - 1;
|
|
156
|
-
}
|
|
157
|
-
get inputRow() {
|
|
158
|
-
return this.termRows;
|
|
159
|
-
}
|
|
160
|
-
// ── Lifecycle ───────────────────────────────────────────────────────────────
|
|
161
|
-
async start() {
|
|
162
|
-
this.bannerCfg = await loadBannerConfig();
|
|
163
|
-
// Build command metadata for completion
|
|
164
|
-
const template = (0, program_1.createProgram)();
|
|
165
|
-
this.topCmds = template.commands.map((cmd) => cmd.name());
|
|
166
|
-
for (const cmd of template.commands) {
|
|
167
|
-
if (cmd.commands.length > 0) {
|
|
168
|
-
this.subCmds.set(cmd.name(), cmd.commands.map((s) => s.name()));
|
|
169
|
-
}
|
|
170
|
-
}
|
|
171
|
-
// Draw initial screen
|
|
172
|
-
this.setupScreen();
|
|
173
|
-
this.drawInputLine();
|
|
174
|
-
// Enter raw mode
|
|
175
|
-
if (process.stdin.isTTY) {
|
|
176
|
-
process.stdin.setRawMode(true);
|
|
177
|
-
}
|
|
178
|
-
process.stdin.resume();
|
|
179
|
-
process.stdin.setEncoding("utf8");
|
|
180
|
-
process.stdin.on("data", this.boundKeyHandler);
|
|
181
|
-
// Resize handler
|
|
182
|
-
process.stdout.on("resize", () => {
|
|
183
|
-
this.setupScreen();
|
|
184
|
-
this.drawInputLine();
|
|
185
|
-
});
|
|
186
|
-
// SIGINT (shouldn't fire in raw mode, but just in case)
|
|
187
|
-
process.on("SIGINT", () => this.exitGracefully());
|
|
188
|
-
// Keep alive — process.stdin listener keeps the event loop running
|
|
189
|
-
await new Promise(() => {
|
|
190
|
-
/* never resolves; process.exit() is called on quit */
|
|
191
|
-
});
|
|
192
|
-
}
|
|
193
|
-
// ── Screen setup ────────────────────────────────────────────────────────────
|
|
194
|
-
setupScreen() {
|
|
195
|
-
this.bannerLines = (0, banner_1.getBannerLines)(this.bannerCfg);
|
|
196
|
-
write(ansi.hideCursor);
|
|
197
|
-
write(ansi.clearScreen + ansi.home);
|
|
198
|
-
// Banner
|
|
199
|
-
for (const line of this.bannerLines) {
|
|
200
|
-
write(line + "\n");
|
|
201
|
-
}
|
|
202
|
-
// Separator between banner and output area
|
|
203
|
-
write(chalk_1.default.dim("─".repeat(this.termCols)) + "\n");
|
|
204
|
-
// Set scroll region (output area, leaves last row free for input)
|
|
205
|
-
if (this.scrollTop <= this.scrollBot) {
|
|
206
|
-
write(ansi.scrollRegion(this.scrollTop, this.scrollBot));
|
|
207
|
-
}
|
|
208
|
-
// Position cursor at top of output area
|
|
209
|
-
write(ansi.move(this.scrollTop, 1));
|
|
210
|
-
write(ansi.showCursor);
|
|
211
|
-
}
|
|
212
|
-
// ── Banner repaint (in-place, preserves output area) ────────────────────────
|
|
213
|
-
repaintBanner() {
|
|
214
|
-
write(ansi.hideCursor);
|
|
215
|
-
for (let i = 0; i < this.bannerLines.length; i++) {
|
|
216
|
-
write(ansi.move(i + 1, 1) + ansi.clearToEol + this.bannerLines[i]);
|
|
82
|
+
// ─── REPL entry point (basic readline fallback) ────────────────────────────────
|
|
83
|
+
async function startREPL() {
|
|
84
|
+
if (!process.stdout.isTTY) {
|
|
85
|
+
const bannerCfg = await loadBannerConfig();
|
|
86
|
+
for (const line of (0, banner_1.getBannerLines)(bannerCfg)) {
|
|
87
|
+
process.stdout.write(line + "\n");
|
|
217
88
|
}
|
|
218
|
-
|
|
219
|
-
|
|
220
|
-
write(ansi.move(sepRow, 1) +
|
|
221
|
-
ansi.clearToEol +
|
|
222
|
-
chalk_1.default.dim("─".repeat(this.termCols)));
|
|
223
|
-
write(ansi.showCursor);
|
|
89
|
+
process.stdout.write("Interactive TUI requires a TTY. Use arc402 <command> directly.\n");
|
|
90
|
+
return;
|
|
224
91
|
}
|
|
225
|
-
|
|
226
|
-
|
|
227
|
-
write(
|
|
228
|
-
write(PROMPT_TEXT + this.inputBuffer);
|
|
229
|
-
// Place cursor at correct position within the input
|
|
230
|
-
write(ansi.move(this.inputRow, PROMPT_VIS + 1 + this.cursorPos));
|
|
92
|
+
const bannerCfg = await loadBannerConfig();
|
|
93
|
+
for (const line of (0, banner_1.getBannerLines)(bannerCfg)) {
|
|
94
|
+
process.stdout.write(line + "\n");
|
|
231
95
|
}
|
|
232
|
-
|
|
233
|
-
|
|
234
|
-
|
|
235
|
-
|
|
236
|
-
|
|
237
|
-
|
|
238
|
-
|
|
239
|
-
|
|
240
|
-
|
|
241
|
-
|
|
242
|
-
|
|
243
|
-
}
|
|
244
|
-
// Enter
|
|
245
|
-
if (key === "\r" || key === "\n") {
|
|
246
|
-
void this.submit();
|
|
247
|
-
return;
|
|
248
|
-
}
|
|
249
|
-
// Backspace
|
|
250
|
-
if (key === "\u007F" || key === "\b") {
|
|
251
|
-
if (this.cursorPos > 0) {
|
|
252
|
-
this.inputBuffer =
|
|
253
|
-
this.inputBuffer.slice(0, this.cursorPos - 1) +
|
|
254
|
-
this.inputBuffer.slice(this.cursorPos);
|
|
255
|
-
this.cursorPos--;
|
|
256
|
-
this.drawInputLine();
|
|
257
|
-
}
|
|
96
|
+
const rl = readline_1.default.createInterface({
|
|
97
|
+
input: process.stdin,
|
|
98
|
+
output: process.stdout,
|
|
99
|
+
prompt: PROMPT,
|
|
100
|
+
terminal: true,
|
|
101
|
+
});
|
|
102
|
+
rl.prompt();
|
|
103
|
+
rl.on("line", async (input) => {
|
|
104
|
+
const trimmed = input.trim();
|
|
105
|
+
if (!trimmed) {
|
|
106
|
+
rl.prompt();
|
|
258
107
|
return;
|
|
259
108
|
}
|
|
260
|
-
|
|
261
|
-
|
|
262
|
-
|
|
263
|
-
this.inputBuffer =
|
|
264
|
-
this.inputBuffer.slice(0, this.cursorPos) +
|
|
265
|
-
this.inputBuffer.slice(this.cursorPos + 1);
|
|
266
|
-
this.drawInputLine();
|
|
267
|
-
}
|
|
268
|
-
return;
|
|
109
|
+
if (trimmed === "exit" || trimmed === "quit") {
|
|
110
|
+
process.stdout.write(" " + chalk_1.default.cyanBright("◈") + chalk_1.default.dim(" goodbye") + "\n");
|
|
111
|
+
process.exit(0);
|
|
269
112
|
}
|
|
270
|
-
|
|
271
|
-
|
|
272
|
-
|
|
273
|
-
|
|
274
|
-
this.historyIdx = this.history.length - 1;
|
|
275
|
-
}
|
|
276
|
-
else if (this.historyIdx > 0) {
|
|
277
|
-
this.historyIdx--;
|
|
278
|
-
}
|
|
279
|
-
if (this.historyIdx >= 0) {
|
|
280
|
-
this.inputBuffer = this.history[this.historyIdx];
|
|
281
|
-
this.cursorPos = this.inputBuffer.length;
|
|
282
|
-
this.drawInputLine();
|
|
113
|
+
if (trimmed === "clear") {
|
|
114
|
+
process.stdout.write("\x1b[2J\x1b[H");
|
|
115
|
+
for (const line of (0, banner_1.getBannerLines)(bannerCfg)) {
|
|
116
|
+
process.stdout.write(line + "\n");
|
|
283
117
|
}
|
|
118
|
+
rl.prompt();
|
|
284
119
|
return;
|
|
285
120
|
}
|
|
286
|
-
//
|
|
287
|
-
|
|
288
|
-
if (this.historyIdx >= 0) {
|
|
289
|
-
this.historyIdx++;
|
|
290
|
-
if (this.historyIdx >= this.history.length) {
|
|
291
|
-
this.historyIdx = -1;
|
|
292
|
-
this.inputBuffer = this.historyTemp;
|
|
293
|
-
}
|
|
294
|
-
else {
|
|
295
|
-
this.inputBuffer = this.history[this.historyIdx];
|
|
296
|
-
}
|
|
297
|
-
this.cursorPos = this.inputBuffer.length;
|
|
298
|
-
this.drawInputLine();
|
|
299
|
-
}
|
|
300
|
-
return;
|
|
301
|
-
}
|
|
302
|
-
// Right arrow
|
|
303
|
-
if (key === "\x1b[C") {
|
|
304
|
-
if (this.cursorPos < this.inputBuffer.length) {
|
|
305
|
-
this.cursorPos++;
|
|
306
|
-
this.drawInputLine();
|
|
307
|
-
}
|
|
308
|
-
return;
|
|
309
|
-
}
|
|
310
|
-
// Left arrow
|
|
311
|
-
if (key === "\x1b[D") {
|
|
312
|
-
if (this.cursorPos > 0) {
|
|
313
|
-
this.cursorPos--;
|
|
314
|
-
this.drawInputLine();
|
|
315
|
-
}
|
|
316
|
-
return;
|
|
317
|
-
}
|
|
318
|
-
// Home / Ctrl+A
|
|
319
|
-
if (key === "\x1b[H" || key === "\u0001") {
|
|
320
|
-
this.cursorPos = 0;
|
|
321
|
-
this.drawInputLine();
|
|
322
|
-
return;
|
|
323
|
-
}
|
|
324
|
-
// End / Ctrl+E
|
|
325
|
-
if (key === "\x1b[F" || key === "\u0005") {
|
|
326
|
-
this.cursorPos = this.inputBuffer.length;
|
|
327
|
-
this.drawInputLine();
|
|
328
|
-
return;
|
|
329
|
-
}
|
|
330
|
-
// Ctrl+U — clear line
|
|
331
|
-
if (key === "\u0015") {
|
|
332
|
-
this.inputBuffer = "";
|
|
333
|
-
this.cursorPos = 0;
|
|
334
|
-
this.drawInputLine();
|
|
335
|
-
return;
|
|
336
|
-
}
|
|
337
|
-
// Ctrl+K — kill to end
|
|
338
|
-
if (key === "\u000B") {
|
|
339
|
-
this.inputBuffer = this.inputBuffer.slice(0, this.cursorPos);
|
|
340
|
-
this.drawInputLine();
|
|
341
|
-
return;
|
|
342
|
-
}
|
|
343
|
-
// Tab — completion
|
|
344
|
-
if (key === "\t") {
|
|
345
|
-
this.handleTab();
|
|
346
|
-
return;
|
|
347
|
-
}
|
|
348
|
-
// Printable characters
|
|
349
|
-
if (key >= " " && !key.startsWith("\x1b")) {
|
|
350
|
-
this.inputBuffer =
|
|
351
|
-
this.inputBuffer.slice(0, this.cursorPos) +
|
|
352
|
-
key +
|
|
353
|
-
this.inputBuffer.slice(this.cursorPos);
|
|
354
|
-
this.cursorPos += key.length;
|
|
355
|
-
this.drawInputLine();
|
|
356
|
-
}
|
|
357
|
-
}
|
|
358
|
-
// ── Tab completion ───────────────────────────────────────────────────────────
|
|
359
|
-
handleTab() {
|
|
360
|
-
const completions = getCompletions(this.inputBuffer, this.topCmds, this.subCmds);
|
|
361
|
-
if (completions.length === 0)
|
|
362
|
-
return;
|
|
363
|
-
if (completions.length === 1) {
|
|
364
|
-
this.inputBuffer = completions[0] + " ";
|
|
365
|
-
this.cursorPos = this.inputBuffer.length;
|
|
366
|
-
this.drawInputLine();
|
|
367
|
-
return;
|
|
368
|
-
}
|
|
369
|
-
// Find common prefix
|
|
370
|
-
const common = completions.reduce((a, b) => {
|
|
371
|
-
let i = 0;
|
|
372
|
-
while (i < a.length && i < b.length && a[i] === b[i])
|
|
373
|
-
i++;
|
|
374
|
-
return a.slice(0, i);
|
|
375
|
-
});
|
|
376
|
-
if (common.length > this.inputBuffer.trimStart().length) {
|
|
377
|
-
this.inputBuffer = common;
|
|
378
|
-
this.cursorPos = common.length;
|
|
379
|
-
}
|
|
380
|
-
// Show options in output area
|
|
381
|
-
this.writeOutput("\n" + chalk_1.default.dim(completions.join(" ")) + "\n");
|
|
382
|
-
this.drawInputLine();
|
|
383
|
-
}
|
|
384
|
-
// ── Write to output area ─────────────────────────────────────────────────────
|
|
385
|
-
writeOutput(text) {
|
|
386
|
-
// Move cursor to bottom of scroll region to ensure scroll-down works
|
|
387
|
-
write(ansi.move(this.scrollBot, 1));
|
|
388
|
-
write(text);
|
|
389
|
-
}
|
|
390
|
-
// ── Submit line ──────────────────────────────────────────────────────────────
|
|
391
|
-
async submit() {
|
|
392
|
-
const input = this.inputBuffer.trim();
|
|
393
|
-
this.inputBuffer = "";
|
|
394
|
-
this.cursorPos = 0;
|
|
395
|
-
this.historyIdx = -1;
|
|
396
|
-
if (!input) {
|
|
397
|
-
this.drawInputLine();
|
|
398
|
-
return;
|
|
399
|
-
}
|
|
400
|
-
// Add to history
|
|
401
|
-
if (input !== this.history[this.history.length - 1]) {
|
|
402
|
-
this.history.push(input);
|
|
403
|
-
}
|
|
404
|
-
// Echo the input into the output area
|
|
405
|
-
this.writeOutput("\n" + chalk_1.default.dim("◈ ") + chalk_1.default.white(input) + "\n");
|
|
406
|
-
// ── Built-in commands ──────────────────────────────────────────────────────
|
|
407
|
-
if (input === "exit" || input === "quit") {
|
|
408
|
-
this.exitGracefully();
|
|
409
|
-
return;
|
|
410
|
-
}
|
|
411
|
-
if (input === "clear") {
|
|
412
|
-
this.bannerCfg = await loadBannerConfig();
|
|
413
|
-
this.setupScreen();
|
|
414
|
-
this.drawInputLine();
|
|
415
|
-
return;
|
|
416
|
-
}
|
|
417
|
-
if (input === "status") {
|
|
418
|
-
await this.runStatus();
|
|
419
|
-
this.afterCommand();
|
|
420
|
-
return;
|
|
421
|
-
}
|
|
422
|
-
if (input === "help") {
|
|
423
|
-
await this.runHelp();
|
|
424
|
-
this.afterCommand();
|
|
425
|
-
return;
|
|
426
|
-
}
|
|
427
|
-
// ── Chat mode detection ────────────────────────────────────────────────────
|
|
428
|
-
const firstWord = input.split(/\s+/)[0];
|
|
429
|
-
const allKnown = [...BUILTIN_CMDS, ...this.topCmds];
|
|
430
|
-
if (!allKnown.includes(firstWord)) {
|
|
431
|
-
this.writeOutput(chalk_1.default.dim("\n ◈ Chat coming soon — type a command or help\n"));
|
|
432
|
-
this.afterCommand();
|
|
433
|
-
return;
|
|
434
|
-
}
|
|
435
|
-
// ── Dispatch to commander ──────────────────────────────────────────────────
|
|
436
|
-
this.commandRunning = true;
|
|
437
|
-
// Move output cursor to bottom of scroll region
|
|
438
|
-
write(ansi.move(this.scrollBot, 1));
|
|
439
|
-
// Suspend TUI stdin so interactive commands (prompts, readline) work cleanly
|
|
440
|
-
process.stdin.removeListener("data", this.boundKeyHandler);
|
|
441
|
-
const tokens = parseTokens(input);
|
|
121
|
+
// Dispatch to commander
|
|
122
|
+
const tokens = parseTokens(trimmed);
|
|
442
123
|
const prog = (0, program_1.createProgram)();
|
|
443
124
|
prog.exitOverride();
|
|
444
125
|
prog.configureOutput({
|
|
445
126
|
writeOut: (str) => process.stdout.write(str),
|
|
446
127
|
writeErr: (str) => process.stderr.write(str),
|
|
447
128
|
});
|
|
448
|
-
const origExit = process.exit;
|
|
449
|
-
process.exit = ((code) => {
|
|
450
|
-
throw new REPLExitSignal(code ?? 0);
|
|
451
|
-
});
|
|
452
129
|
try {
|
|
453
130
|
await prog.parseAsync(["node", "arc402", ...tokens]);
|
|
454
131
|
}
|
|
455
132
|
catch (err) {
|
|
456
|
-
|
|
457
|
-
|
|
133
|
+
const e = err;
|
|
134
|
+
if (e.code === "commander.helpDisplayed" ||
|
|
135
|
+
e.code === "commander.version" ||
|
|
136
|
+
e.code === "commander.executeSubCommandAsync") {
|
|
137
|
+
// already written
|
|
458
138
|
}
|
|
459
|
-
else {
|
|
460
|
-
|
|
461
|
-
|
|
462
|
-
e.code === "commander.version") {
|
|
463
|
-
// already written
|
|
464
|
-
}
|
|
465
|
-
else if (e.code === "commander.unknownCommand") {
|
|
466
|
-
process.stdout.write(`\n ${colors_1.c.failure} ${chalk_1.default.red(`Unknown command: ${chalk_1.default.white(tokens[0])}`)} \n`);
|
|
467
|
-
process.stdout.write(chalk_1.default.dim(" Type 'help' for available commands\n"));
|
|
468
|
-
}
|
|
469
|
-
else if (e.code?.startsWith("commander.")) {
|
|
470
|
-
process.stdout.write(`\n ${colors_1.c.failure} ${chalk_1.default.red(e.message ?? String(err))}\n`);
|
|
471
|
-
}
|
|
472
|
-
else {
|
|
473
|
-
process.stdout.write(`\n ${colors_1.c.failure} ${chalk_1.default.red(e.message ?? String(err))}\n`);
|
|
474
|
-
}
|
|
475
|
-
}
|
|
476
|
-
}
|
|
477
|
-
finally {
|
|
478
|
-
process.exit = origExit;
|
|
479
|
-
}
|
|
480
|
-
// Restore raw mode + our listener (interactive commands may have toggled it)
|
|
481
|
-
if (process.stdin.isTTY) {
|
|
482
|
-
process.stdin.setRawMode(true);
|
|
483
|
-
}
|
|
484
|
-
process.stdin.on("data", this.boundKeyHandler);
|
|
485
|
-
this.commandRunning = false;
|
|
486
|
-
this.afterCommand();
|
|
487
|
-
}
|
|
488
|
-
// ── After each command: repaint banner + input ───────────────────────────────
|
|
489
|
-
afterCommand() {
|
|
490
|
-
this.repaintBanner();
|
|
491
|
-
this.drawInputLine();
|
|
492
|
-
}
|
|
493
|
-
// ── Built-in: status ─────────────────────────────────────────────────────────
|
|
494
|
-
async runStatus() {
|
|
495
|
-
write(ansi.move(this.scrollBot, 1));
|
|
496
|
-
if (!fs_1.default.existsSync(CONFIG_PATH)) {
|
|
497
|
-
process.stdout.write(chalk_1.default.dim("\n No config found. Run 'config init' to get started.\n"));
|
|
498
|
-
return;
|
|
499
|
-
}
|
|
500
|
-
try {
|
|
501
|
-
const raw = JSON.parse(fs_1.default.readFileSync(CONFIG_PATH, "utf-8"));
|
|
502
|
-
process.stdout.write("\n");
|
|
503
|
-
if (raw.network)
|
|
504
|
-
process.stdout.write(` ${chalk_1.default.dim("Network")} ${chalk_1.default.white(raw.network)}\n`);
|
|
505
|
-
if (raw.walletContractAddress) {
|
|
506
|
-
const w = raw.walletContractAddress;
|
|
507
|
-
process.stdout.write(` ${chalk_1.default.dim("Wallet")} ${chalk_1.default.white(`${w.slice(0, 6)}...${w.slice(-4)}`)}\n`);
|
|
139
|
+
else if (e.code === "commander.unknownCommand") {
|
|
140
|
+
process.stdout.write(`\n ${colors_1.c.failure} ${chalk_1.default.red(`Unknown command: ${chalk_1.default.white(tokens[0])}`)} \n`);
|
|
141
|
+
process.stdout.write(chalk_1.default.dim(" Type 'help' for available commands\n"));
|
|
508
142
|
}
|
|
509
|
-
|
|
510
|
-
|
|
511
|
-
// eslint-disable-next-line @typescript-eslint/no-var-requires
|
|
512
|
-
const ethersLib = require("ethers");
|
|
513
|
-
const provider = new ethersLib.ethers.JsonRpcProvider(raw.rpcUrl);
|
|
514
|
-
const bal = await Promise.race([
|
|
515
|
-
provider.getBalance(raw.walletContractAddress),
|
|
516
|
-
new Promise((_, r) => setTimeout(() => r(new Error("timeout")), 2000)),
|
|
517
|
-
]);
|
|
518
|
-
process.stdout.write(` ${chalk_1.default.dim("Balance")} ${chalk_1.default.white(`${parseFloat(ethersLib.ethers.formatEther(bal)).toFixed(4)} ETH`)}\n`);
|
|
519
|
-
}
|
|
520
|
-
catch {
|
|
521
|
-
/* skip */
|
|
522
|
-
}
|
|
143
|
+
else {
|
|
144
|
+
process.stdout.write(`\n ${colors_1.c.failure} ${chalk_1.default.red(e.message ?? String(err))}\n`);
|
|
523
145
|
}
|
|
524
|
-
process.stdout.write("\n");
|
|
525
|
-
}
|
|
526
|
-
catch {
|
|
527
|
-
/* skip */
|
|
528
|
-
}
|
|
529
|
-
}
|
|
530
|
-
// ── Built-in: help ────────────────────────────────────────────────────────────
|
|
531
|
-
async runHelp() {
|
|
532
|
-
write(ansi.move(this.scrollBot, 1));
|
|
533
|
-
process.stdin.removeListener("data", this.boundKeyHandler);
|
|
534
|
-
const prog = (0, program_1.createProgram)();
|
|
535
|
-
prog.exitOverride();
|
|
536
|
-
prog.configureOutput({
|
|
537
|
-
writeOut: (str) => process.stdout.write(str),
|
|
538
|
-
writeErr: (str) => process.stderr.write(str),
|
|
539
|
-
});
|
|
540
|
-
try {
|
|
541
|
-
await prog.parseAsync(["node", "arc402", "--help"]);
|
|
542
|
-
}
|
|
543
|
-
catch {
|
|
544
|
-
/* commander throws after printing help */
|
|
545
|
-
}
|
|
546
|
-
if (process.stdin.isTTY)
|
|
547
|
-
process.stdin.setRawMode(true);
|
|
548
|
-
process.stdin.on("data", this.boundKeyHandler);
|
|
549
|
-
}
|
|
550
|
-
// ── Exit ──────────────────────────────────────────────────────────────────────
|
|
551
|
-
exitGracefully() {
|
|
552
|
-
write(ansi.move(this.inputRow, 1) + ansi.clearLine);
|
|
553
|
-
write(" " + chalk_1.default.cyanBright("◈") + chalk_1.default.dim(" goodbye") + "\n");
|
|
554
|
-
write(ansi.resetScroll);
|
|
555
|
-
write(ansi.showCursor);
|
|
556
|
-
if (process.stdin.isTTY) {
|
|
557
|
-
process.stdin.setRawMode(false);
|
|
558
146
|
}
|
|
147
|
+
process.stdout.write("\n");
|
|
148
|
+
rl.prompt();
|
|
149
|
+
});
|
|
150
|
+
rl.on("close", () => {
|
|
151
|
+
process.stdout.write("\n " + chalk_1.default.cyanBright("◈") + chalk_1.default.dim(" goodbye") + "\n");
|
|
559
152
|
process.exit(0);
|
|
560
|
-
}
|
|
561
|
-
|
|
562
|
-
|
|
563
|
-
|
|
564
|
-
|
|
565
|
-
// Non-TTY (piped): fall back to minimal line-mode output
|
|
566
|
-
const bannerCfg = await loadBannerConfig();
|
|
567
|
-
for (const line of (0, banner_1.getBannerLines)(bannerCfg)) {
|
|
568
|
-
process.stdout.write(line + "\n");
|
|
569
|
-
}
|
|
570
|
-
process.stdout.write("Interactive TUI requires a TTY. Use arc402 <command> directly.\n");
|
|
571
|
-
return;
|
|
572
|
-
}
|
|
573
|
-
const tui = new TUI();
|
|
574
|
-
await tui.start();
|
|
153
|
+
});
|
|
154
|
+
// Keep alive
|
|
155
|
+
await new Promise(() => {
|
|
156
|
+
/* readline keeps event loop alive */
|
|
157
|
+
});
|
|
575
158
|
}
|
|
576
159
|
//# sourceMappingURL=repl.js.map
|