@fiber-pay/cli 0.1.0-rc.2 → 0.1.0-rc.4
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 +1 -1
- package/dist/cli.js +625 -133
- package/dist/cli.js.map +1 -1
- package/package.json +6 -4
package/dist/cli.js
CHANGED
|
@@ -965,13 +965,13 @@ import { existsSync as existsSync3, mkdirSync, readFileSync as readFileSync3, wr
|
|
|
965
965
|
import { join as join3 } from "path";
|
|
966
966
|
|
|
967
967
|
// src/lib/config-templates.ts
|
|
968
|
-
var
|
|
968
|
+
var TESTNET_CONFIG_TEMPLATE_V071 = `# This configuration file only contains the necessary configurations for the testnet deployment.
|
|
969
969
|
# All options' descriptions can be found via \`fnn --help\` and be overridden by command line arguments or environment variables.
|
|
970
970
|
fiber:
|
|
971
|
-
listening_addr: "/ip4/
|
|
971
|
+
listening_addr: "/ip4/0.0.0.0/tcp/8228"
|
|
972
972
|
bootnode_addrs:
|
|
973
973
|
- "/ip4/54.179.226.154/tcp/8228/p2p/Qmes1EBD4yNo9Ywkfe6eRw9tG1nVNGLDmMud1xJMsoYFKy"
|
|
974
|
-
- "/ip4/
|
|
974
|
+
- "/ip4/16.163.7.105/tcp/8228/p2p/QmdyQWjPtbK4NWWsvy8s69NGJaQULwgeQDT5ZpNDrTNaeV"
|
|
975
975
|
announce_listening_addr: true
|
|
976
976
|
announced_addrs:
|
|
977
977
|
# If you want to announce your fiber node public address to the network, you need to add the address here, please change the ip to your public ip accordingly.
|
|
@@ -1037,7 +1037,7 @@ services:
|
|
|
1037
1037
|
- rpc
|
|
1038
1038
|
- ckb
|
|
1039
1039
|
`;
|
|
1040
|
-
var
|
|
1040
|
+
var MAINNET_CONFIG_TEMPLATE_V071 = `# This configuration file only contains the necessary configurations for the mainnet deployment.
|
|
1041
1041
|
# All options' descriptions can be found via \`fnn --help\` and be overridden by command line arguments or environment variables.
|
|
1042
1042
|
fiber:
|
|
1043
1043
|
listening_addr: "/ip4/0.0.0.0/tcp/8228"
|
|
@@ -1113,7 +1113,7 @@ services:
|
|
|
1113
1113
|
- ckb
|
|
1114
1114
|
`;
|
|
1115
1115
|
function getConfigTemplate(network) {
|
|
1116
|
-
return network === "mainnet" ?
|
|
1116
|
+
return network === "mainnet" ? MAINNET_CONFIG_TEMPLATE_V071 : TESTNET_CONFIG_TEMPLATE_V071;
|
|
1117
1117
|
}
|
|
1118
1118
|
|
|
1119
1119
|
// src/lib/config.ts
|
|
@@ -2032,7 +2032,7 @@ import { existsSync as existsSync6 } from "fs";
|
|
|
2032
2032
|
import { Command as Command6 } from "commander";
|
|
2033
2033
|
|
|
2034
2034
|
// src/lib/log-files.ts
|
|
2035
|
-
import { existsSync as existsSync5,
|
|
2035
|
+
import { closeSync, createReadStream, existsSync as existsSync5, openSync, readSync, statSync } from "fs";
|
|
2036
2036
|
import { join as join4 } from "path";
|
|
2037
2037
|
function resolvePersistedLogPaths(dataDir, meta) {
|
|
2038
2038
|
return {
|
|
@@ -2068,9 +2068,80 @@ function readLastLines(filePath, maxLines) {
|
|
|
2068
2068
|
if (!existsSync5(filePath)) {
|
|
2069
2069
|
return [];
|
|
2070
2070
|
}
|
|
2071
|
-
|
|
2072
|
-
|
|
2073
|
-
|
|
2071
|
+
if (!Number.isFinite(maxLines) || maxLines <= 0) {
|
|
2072
|
+
return [];
|
|
2073
|
+
}
|
|
2074
|
+
let fd;
|
|
2075
|
+
try {
|
|
2076
|
+
fd = openSync(filePath, "r");
|
|
2077
|
+
const size = statSync(filePath).size;
|
|
2078
|
+
if (size <= 0) {
|
|
2079
|
+
return [];
|
|
2080
|
+
}
|
|
2081
|
+
const chunkSize = 64 * 1024;
|
|
2082
|
+
let position = size;
|
|
2083
|
+
const chunks = [];
|
|
2084
|
+
let newlineCount = 0;
|
|
2085
|
+
while (position > 0 && newlineCount <= maxLines) {
|
|
2086
|
+
const start = Math.max(0, position - chunkSize);
|
|
2087
|
+
const bytesToRead = position - start;
|
|
2088
|
+
const buffer = Buffer.alloc(bytesToRead);
|
|
2089
|
+
const bytesRead = readSync(fd, buffer, 0, bytesToRead, start);
|
|
2090
|
+
const chunk = buffer.toString("utf8", 0, bytesRead);
|
|
2091
|
+
chunks.unshift(chunk);
|
|
2092
|
+
for (let index = 0; index < chunk.length; index += 1) {
|
|
2093
|
+
if (chunk.charCodeAt(index) === 10) {
|
|
2094
|
+
newlineCount += 1;
|
|
2095
|
+
}
|
|
2096
|
+
}
|
|
2097
|
+
position = start;
|
|
2098
|
+
}
|
|
2099
|
+
const content = chunks.join("");
|
|
2100
|
+
const lines = content.split(/\r?\n/).filter((line) => line.length > 0);
|
|
2101
|
+
return lines.slice(-maxLines);
|
|
2102
|
+
} finally {
|
|
2103
|
+
if (fd !== void 0) {
|
|
2104
|
+
try {
|
|
2105
|
+
closeSync(fd);
|
|
2106
|
+
} catch {
|
|
2107
|
+
}
|
|
2108
|
+
}
|
|
2109
|
+
}
|
|
2110
|
+
}
|
|
2111
|
+
async function readAppendedLines(filePath, offset, remainder = "") {
|
|
2112
|
+
if (!existsSync5(filePath)) {
|
|
2113
|
+
return { lines: [], nextOffset: 0, remainder: "" };
|
|
2114
|
+
}
|
|
2115
|
+
const size = statSync(filePath).size;
|
|
2116
|
+
const safeOffset = size < offset ? 0 : offset;
|
|
2117
|
+
if (safeOffset >= size) {
|
|
2118
|
+
return { lines: [], nextOffset: size, remainder };
|
|
2119
|
+
}
|
|
2120
|
+
const stream = createReadStream(filePath, {
|
|
2121
|
+
encoding: "utf8",
|
|
2122
|
+
start: safeOffset,
|
|
2123
|
+
end: size - 1
|
|
2124
|
+
});
|
|
2125
|
+
const lines = [];
|
|
2126
|
+
let pending = remainder;
|
|
2127
|
+
let bytesReadTotal = 0;
|
|
2128
|
+
for await (const chunk of stream) {
|
|
2129
|
+
const chunkText = String(chunk);
|
|
2130
|
+
bytesReadTotal += Buffer.byteLength(chunkText, "utf8");
|
|
2131
|
+
const merged = `${pending}${chunkText}`;
|
|
2132
|
+
const parts = merged.split(/\r?\n/);
|
|
2133
|
+
pending = parts.pop() ?? "";
|
|
2134
|
+
for (const line of parts) {
|
|
2135
|
+
if (line.length > 0) {
|
|
2136
|
+
lines.push(line);
|
|
2137
|
+
}
|
|
2138
|
+
}
|
|
2139
|
+
}
|
|
2140
|
+
return {
|
|
2141
|
+
lines,
|
|
2142
|
+
nextOffset: safeOffset + bytesReadTotal,
|
|
2143
|
+
remainder: pending
|
|
2144
|
+
};
|
|
2074
2145
|
}
|
|
2075
2146
|
|
|
2076
2147
|
// src/commands/job.ts
|
|
@@ -2388,7 +2459,7 @@ ${title}: ${filePath}`);
|
|
|
2388
2459
|
}
|
|
2389
2460
|
|
|
2390
2461
|
// src/commands/logs.ts
|
|
2391
|
-
import { existsSync as existsSync7 } from "fs";
|
|
2462
|
+
import { existsSync as existsSync7, statSync as statSync2 } from "fs";
|
|
2392
2463
|
import { formatRuntimeAlert } from "@fiber-pay/runtime";
|
|
2393
2464
|
import { Command as Command7 } from "commander";
|
|
2394
2465
|
var ALLOWED_SOURCES = /* @__PURE__ */ new Set([
|
|
@@ -2550,7 +2621,8 @@ Following logs (interval: ${intervalMs}ms). Press Ctrl+C to stop.`);
|
|
|
2550
2621
|
{
|
|
2551
2622
|
title: entry.title,
|
|
2552
2623
|
path: entry.path,
|
|
2553
|
-
|
|
2624
|
+
offset: entry.exists ? statSync2(entry.path).size : 0,
|
|
2625
|
+
remainder: ""
|
|
2554
2626
|
}
|
|
2555
2627
|
])
|
|
2556
2628
|
);
|
|
@@ -2565,26 +2637,41 @@ Following logs (interval: ${intervalMs}ms). Press Ctrl+C to stop.`);
|
|
|
2565
2637
|
console.log("\nStopped following logs.");
|
|
2566
2638
|
resolve2();
|
|
2567
2639
|
};
|
|
2640
|
+
let polling = false;
|
|
2568
2641
|
const timer = setInterval(() => {
|
|
2569
|
-
|
|
2570
|
-
|
|
2571
|
-
if (!state) continue;
|
|
2572
|
-
if (!existsSync7(state.path)) {
|
|
2573
|
-
continue;
|
|
2574
|
-
}
|
|
2575
|
-
const allLines = readLastLines(state.path, Number.MAX_SAFE_INTEGER);
|
|
2576
|
-
const total = allLines.length;
|
|
2577
|
-
const fromIndex = total < state.seenLines ? 0 : state.seenLines;
|
|
2578
|
-
const newLines = allLines.slice(fromIndex);
|
|
2579
|
-
if (newLines.length === 0) {
|
|
2580
|
-
continue;
|
|
2581
|
-
}
|
|
2582
|
-
for (const line of newLines) {
|
|
2583
|
-
const output = target.source === "runtime" ? formatRuntimeAlertHuman(line) : line;
|
|
2584
|
-
console.log(`[${state.title}] ${output}`);
|
|
2585
|
-
}
|
|
2586
|
-
state.seenLines = total;
|
|
2642
|
+
if (polling) {
|
|
2643
|
+
return;
|
|
2587
2644
|
}
|
|
2645
|
+
polling = true;
|
|
2646
|
+
void (async () => {
|
|
2647
|
+
for (const target of targets) {
|
|
2648
|
+
const state = states.get(target.source);
|
|
2649
|
+
if (!state) continue;
|
|
2650
|
+
if (!existsSync7(state.path)) {
|
|
2651
|
+
state.offset = 0;
|
|
2652
|
+
state.remainder = "";
|
|
2653
|
+
continue;
|
|
2654
|
+
}
|
|
2655
|
+
const result = await readAppendedLines(state.path, state.offset, state.remainder);
|
|
2656
|
+
const newLines = result.lines;
|
|
2657
|
+
if (newLines.length === 0) {
|
|
2658
|
+
state.offset = result.nextOffset;
|
|
2659
|
+
state.remainder = result.remainder;
|
|
2660
|
+
continue;
|
|
2661
|
+
}
|
|
2662
|
+
for (const line of newLines) {
|
|
2663
|
+
const output = target.source === "runtime" ? formatRuntimeAlertHuman(line) : line;
|
|
2664
|
+
console.log(`[${state.title}] ${output}`);
|
|
2665
|
+
}
|
|
2666
|
+
state.offset = result.nextOffset;
|
|
2667
|
+
state.remainder = result.remainder;
|
|
2668
|
+
}
|
|
2669
|
+
})().catch((error) => {
|
|
2670
|
+
const message = error instanceof Error ? error.message : "Failed to read appended logs";
|
|
2671
|
+
console.error(`Error: ${message}`);
|
|
2672
|
+
}).finally(() => {
|
|
2673
|
+
polling = false;
|
|
2674
|
+
});
|
|
2588
2675
|
}, intervalMs);
|
|
2589
2676
|
process.on("SIGINT", stop);
|
|
2590
2677
|
process.on("SIGTERM", stop);
|
|
@@ -2596,11 +2683,122 @@ Following logs (interval: ${intervalMs}ms). Press Ctrl+C to stop.`);
|
|
|
2596
2683
|
import { nodeIdToPeerId as nodeIdToPeerId2, scriptToAddress as scriptToAddress2 } from "@fiber-pay/sdk";
|
|
2597
2684
|
import { Command as Command8 } from "commander";
|
|
2598
2685
|
|
|
2686
|
+
// src/lib/node-start.ts
|
|
2687
|
+
import { spawn } from "child_process";
|
|
2688
|
+
import { appendFileSync, mkdirSync as mkdirSync2 } from "fs";
|
|
2689
|
+
import { join as join5 } from "path";
|
|
2690
|
+
import {
|
|
2691
|
+
createKeyManager,
|
|
2692
|
+
ensureFiberBinary,
|
|
2693
|
+
getDefaultBinaryPath,
|
|
2694
|
+
ProcessManager
|
|
2695
|
+
} from "@fiber-pay/node";
|
|
2696
|
+
import { startRuntimeService } from "@fiber-pay/runtime";
|
|
2697
|
+
|
|
2698
|
+
// src/lib/bootnode.ts
|
|
2699
|
+
import { existsSync as existsSync8, readFileSync as readFileSync5 } from "fs";
|
|
2700
|
+
import { parse as parseYaml } from "yaml";
|
|
2701
|
+
function extractBootnodeAddrs(configFilePath) {
|
|
2702
|
+
if (!existsSync8(configFilePath)) return [];
|
|
2703
|
+
try {
|
|
2704
|
+
const content = readFileSync5(configFilePath, "utf-8");
|
|
2705
|
+
const doc = parseYaml(content);
|
|
2706
|
+
const addrs = doc?.fiber?.bootnode_addrs;
|
|
2707
|
+
if (!Array.isArray(addrs)) return [];
|
|
2708
|
+
return addrs.filter((a) => typeof a === "string" && a.startsWith("/ip"));
|
|
2709
|
+
} catch {
|
|
2710
|
+
return [];
|
|
2711
|
+
}
|
|
2712
|
+
}
|
|
2713
|
+
async function autoConnectBootnodes(rpc, bootnodes) {
|
|
2714
|
+
if (bootnodes.length === 0) return;
|
|
2715
|
+
console.log(`\u{1F517} Connecting to ${bootnodes.length} bootnode(s)...`);
|
|
2716
|
+
for (const addr of bootnodes) {
|
|
2717
|
+
const shortId = addr.match(/\/p2p\/(.+)$/)?.[1]?.slice(0, 12) || addr.slice(-12);
|
|
2718
|
+
try {
|
|
2719
|
+
await rpc.connectPeer({ address: addr });
|
|
2720
|
+
console.log(` \u2705 Connected to ${shortId}...`);
|
|
2721
|
+
} catch (err) {
|
|
2722
|
+
const msg = err instanceof Error ? err.message : String(err);
|
|
2723
|
+
if (msg.toLowerCase().includes("already")) {
|
|
2724
|
+
console.log(` \u2705 Already connected to ${shortId}...`);
|
|
2725
|
+
} else {
|
|
2726
|
+
console.error(` \u26A0\uFE0F Failed to connect to ${shortId}...: ${msg}`);
|
|
2727
|
+
}
|
|
2728
|
+
}
|
|
2729
|
+
}
|
|
2730
|
+
}
|
|
2731
|
+
|
|
2732
|
+
// src/lib/node-migration.ts
|
|
2733
|
+
import { dirname } from "path";
|
|
2734
|
+
import { BinaryManager, MigrationManager } from "@fiber-pay/node";
|
|
2735
|
+
|
|
2736
|
+
// src/lib/migration-utils.ts
|
|
2737
|
+
function replaceRawMigrateHint(message) {
|
|
2738
|
+
return message.replace(
|
|
2739
|
+
/Fiber need to run some database migrations, please run `fnn-migrate[^`]*` to start migrations\.?/g,
|
|
2740
|
+
"Fiber database migration is required."
|
|
2741
|
+
);
|
|
2742
|
+
}
|
|
2743
|
+
function normalizeMigrationCheck(check) {
|
|
2744
|
+
return {
|
|
2745
|
+
...check,
|
|
2746
|
+
message: replaceRawMigrateHint(check.message)
|
|
2747
|
+
};
|
|
2748
|
+
}
|
|
2749
|
+
|
|
2750
|
+
// src/lib/node-migration.ts
|
|
2751
|
+
async function runMigrationGuard(opts) {
|
|
2752
|
+
const { dataDir, binaryPath, json } = opts;
|
|
2753
|
+
if (!MigrationManager.storeExists(dataDir)) {
|
|
2754
|
+
return { checked: false, skippedReason: "store does not exist" };
|
|
2755
|
+
}
|
|
2756
|
+
const storePath = MigrationManager.resolveStorePath(dataDir);
|
|
2757
|
+
const binaryDir = dirname(binaryPath);
|
|
2758
|
+
const bm = new BinaryManager(binaryDir);
|
|
2759
|
+
const migrateBinPath = bm.getMigrateBinaryPath();
|
|
2760
|
+
let migrationCheck;
|
|
2761
|
+
try {
|
|
2762
|
+
const migrationManager = new MigrationManager(migrateBinPath);
|
|
2763
|
+
migrationCheck = await migrationManager.check(storePath);
|
|
2764
|
+
} catch {
|
|
2765
|
+
return { checked: false, skippedReason: "fnn-migrate binary not available" };
|
|
2766
|
+
}
|
|
2767
|
+
if (migrationCheck.needed) {
|
|
2768
|
+
const message = migrationCheck.valid ? "Database migration required. Run `fiber-pay node upgrade --force-migrate` before starting." : replaceRawMigrateHint(migrationCheck.message);
|
|
2769
|
+
if (json) {
|
|
2770
|
+
printJsonError({
|
|
2771
|
+
code: "MIGRATION_REQUIRED",
|
|
2772
|
+
message,
|
|
2773
|
+
recoverable: true,
|
|
2774
|
+
suggestion: `Back up your store first (directory: "${storePath}"). Then run \`fiber-pay node upgrade --force-migrate\`. If migration still fails, close channels on the old fnn version, remove the store, and restart with a fresh store. If backup exists, restore it to roll back.`,
|
|
2775
|
+
details: {
|
|
2776
|
+
storePath,
|
|
2777
|
+
migrationCheck: {
|
|
2778
|
+
...migrationCheck,
|
|
2779
|
+
message
|
|
2780
|
+
}
|
|
2781
|
+
}
|
|
2782
|
+
});
|
|
2783
|
+
} else {
|
|
2784
|
+
console.error(`\u274C ${message}`);
|
|
2785
|
+
console.error(` 1) Back up store directory: ${storePath}`);
|
|
2786
|
+
console.error(" 2) Run: fiber-pay node upgrade --force-migrate");
|
|
2787
|
+
console.error(
|
|
2788
|
+
" 3) If it still fails, close channels on old fnn, remove store, then restart."
|
|
2789
|
+
);
|
|
2790
|
+
console.error(" 4) If backup exists, restore it to roll back.");
|
|
2791
|
+
}
|
|
2792
|
+
process.exit(1);
|
|
2793
|
+
}
|
|
2794
|
+
return { checked: true, migrationCheck };
|
|
2795
|
+
}
|
|
2796
|
+
|
|
2599
2797
|
// src/lib/node-runtime-daemon.ts
|
|
2600
2798
|
import { spawnSync } from "child_process";
|
|
2601
|
-
import { existsSync as
|
|
2799
|
+
import { existsSync as existsSync9 } from "fs";
|
|
2602
2800
|
function getCustomBinaryState(binaryPath) {
|
|
2603
|
-
const exists =
|
|
2801
|
+
const exists = existsSync9(binaryPath);
|
|
2604
2802
|
if (!exists) {
|
|
2605
2803
|
return { path: binaryPath, ready: false, version: "unknown" };
|
|
2606
2804
|
}
|
|
@@ -2690,52 +2888,6 @@ function stopRuntimeDaemonFromNode(params) {
|
|
|
2690
2888
|
);
|
|
2691
2889
|
}
|
|
2692
2890
|
|
|
2693
|
-
// src/lib/node-start.ts
|
|
2694
|
-
import { spawn } from "child_process";
|
|
2695
|
-
import { appendFileSync, mkdirSync as mkdirSync2 } from "fs";
|
|
2696
|
-
import { join as join5 } from "path";
|
|
2697
|
-
import {
|
|
2698
|
-
ensureFiberBinary,
|
|
2699
|
-
getDefaultBinaryPath,
|
|
2700
|
-
ProcessManager
|
|
2701
|
-
} from "@fiber-pay/node";
|
|
2702
|
-
import { startRuntimeService } from "@fiber-pay/runtime";
|
|
2703
|
-
import { createKeyManager } from "@fiber-pay/sdk";
|
|
2704
|
-
|
|
2705
|
-
// src/lib/bootnode.ts
|
|
2706
|
-
import { existsSync as existsSync9, readFileSync as readFileSync6 } from "fs";
|
|
2707
|
-
import { parse as parseYaml } from "yaml";
|
|
2708
|
-
function extractBootnodeAddrs(configFilePath) {
|
|
2709
|
-
if (!existsSync9(configFilePath)) return [];
|
|
2710
|
-
try {
|
|
2711
|
-
const content = readFileSync6(configFilePath, "utf-8");
|
|
2712
|
-
const doc = parseYaml(content);
|
|
2713
|
-
const addrs = doc?.fiber?.bootnode_addrs;
|
|
2714
|
-
if (!Array.isArray(addrs)) return [];
|
|
2715
|
-
return addrs.filter((a) => typeof a === "string" && a.startsWith("/ip"));
|
|
2716
|
-
} catch {
|
|
2717
|
-
return [];
|
|
2718
|
-
}
|
|
2719
|
-
}
|
|
2720
|
-
async function autoConnectBootnodes(rpc, bootnodes) {
|
|
2721
|
-
if (bootnodes.length === 0) return;
|
|
2722
|
-
console.log(`\u{1F517} Connecting to ${bootnodes.length} bootnode(s)...`);
|
|
2723
|
-
for (const addr of bootnodes) {
|
|
2724
|
-
const shortId = addr.match(/\/p2p\/(.+)$/)?.[1]?.slice(0, 12) || addr.slice(-12);
|
|
2725
|
-
try {
|
|
2726
|
-
await rpc.connectPeer({ address: addr });
|
|
2727
|
-
console.log(` \u2705 Connected to ${shortId}...`);
|
|
2728
|
-
} catch (err) {
|
|
2729
|
-
const msg = err instanceof Error ? err.message : String(err);
|
|
2730
|
-
if (msg.toLowerCase().includes("already")) {
|
|
2731
|
-
console.log(` \u2705 Already connected to ${shortId}...`);
|
|
2732
|
-
} else {
|
|
2733
|
-
console.error(` \u26A0\uFE0F Failed to connect to ${shortId}...: ${msg}`);
|
|
2734
|
-
}
|
|
2735
|
-
}
|
|
2736
|
-
}
|
|
2737
|
-
}
|
|
2738
|
-
|
|
2739
2891
|
// src/lib/node-start.ts
|
|
2740
2892
|
async function runNodeStartCommand(config, options) {
|
|
2741
2893
|
const json = Boolean(options.json);
|
|
@@ -2864,6 +3016,19 @@ async function runNodeStartCommand(config, options) {
|
|
|
2864
3016
|
console.log(`\u{1F9E9} Binary: ${binaryPath}`);
|
|
2865
3017
|
console.log(`\u{1F9E9} Version: ${binaryVersion}`);
|
|
2866
3018
|
}
|
|
3019
|
+
const guardResult = await runMigrationGuard({ dataDir: config.dataDir, binaryPath, json });
|
|
3020
|
+
if (guardResult.checked) {
|
|
3021
|
+
emitStage("migration_check", "ok", {
|
|
3022
|
+
storePath: `${config.dataDir}/store`,
|
|
3023
|
+
needed: false
|
|
3024
|
+
});
|
|
3025
|
+
} else {
|
|
3026
|
+
emitStage("migration_check", "ok", {
|
|
3027
|
+
storePath: `${config.dataDir}/store`,
|
|
3028
|
+
skipped: true,
|
|
3029
|
+
reason: guardResult.skippedReason
|
|
3030
|
+
});
|
|
3031
|
+
}
|
|
2867
3032
|
const nodeConfig = {
|
|
2868
3033
|
binaryPath,
|
|
2869
3034
|
dataDir: config.dataDir,
|
|
@@ -3634,67 +3799,334 @@ async function runNodeReadyCommand(config, options) {
|
|
|
3634
3799
|
}
|
|
3635
3800
|
}
|
|
3636
3801
|
|
|
3637
|
-
// src/
|
|
3638
|
-
function
|
|
3639
|
-
const
|
|
3640
|
-
|
|
3641
|
-
|
|
3642
|
-
|
|
3643
|
-
|
|
3644
|
-
|
|
3645
|
-
|
|
3646
|
-
|
|
3647
|
-
|
|
3648
|
-
|
|
3802
|
+
// src/lib/node-stop.ts
|
|
3803
|
+
async function runNodeStopCommand(config, options) {
|
|
3804
|
+
const json = Boolean(options.json);
|
|
3805
|
+
const runtimeMeta = readRuntimeMeta(config.dataDir);
|
|
3806
|
+
const runtimePid = readRuntimePid(config.dataDir);
|
|
3807
|
+
if (runtimeMeta?.daemon && runtimePid && isProcessRunning(runtimePid)) {
|
|
3808
|
+
stopRuntimeDaemonFromNode({ dataDir: config.dataDir, rpcUrl: config.rpcUrl });
|
|
3809
|
+
}
|
|
3810
|
+
removeRuntimeFiles(config.dataDir);
|
|
3811
|
+
const pid = readPidFile(config.dataDir);
|
|
3812
|
+
if (!pid) {
|
|
3813
|
+
if (json) {
|
|
3814
|
+
printJsonError({
|
|
3815
|
+
code: "NODE_NOT_RUNNING",
|
|
3816
|
+
message: "No PID file found. Node may not be running.",
|
|
3817
|
+
recoverable: true,
|
|
3818
|
+
suggestion: "Run `fiber-pay node start` first if you intend to stop a node."
|
|
3819
|
+
});
|
|
3820
|
+
} else {
|
|
3821
|
+
console.log("\u274C No PID file found. Node may not be running.");
|
|
3649
3822
|
}
|
|
3650
|
-
|
|
3651
|
-
|
|
3652
|
-
|
|
3653
|
-
|
|
3654
|
-
|
|
3655
|
-
|
|
3656
|
-
|
|
3657
|
-
|
|
3658
|
-
|
|
3659
|
-
}
|
|
3660
|
-
}
|
|
3661
|
-
|
|
3662
|
-
}
|
|
3663
|
-
process.exit(1);
|
|
3823
|
+
process.exit(1);
|
|
3824
|
+
}
|
|
3825
|
+
if (!isProcessRunning(pid)) {
|
|
3826
|
+
if (json) {
|
|
3827
|
+
printJsonError({
|
|
3828
|
+
code: "NODE_NOT_RUNNING",
|
|
3829
|
+
message: `Process ${pid} is not running. Cleaning up PID file.`,
|
|
3830
|
+
recoverable: true,
|
|
3831
|
+
suggestion: "Start the node again if needed; stale PID has been cleaned.",
|
|
3832
|
+
details: { pid, stalePidFileCleaned: true }
|
|
3833
|
+
});
|
|
3834
|
+
} else {
|
|
3835
|
+
console.log(`\u274C Process ${pid} is not running. Cleaning up PID file.`);
|
|
3664
3836
|
}
|
|
3665
|
-
|
|
3666
|
-
|
|
3667
|
-
|
|
3668
|
-
|
|
3669
|
-
|
|
3670
|
-
|
|
3671
|
-
|
|
3672
|
-
|
|
3673
|
-
|
|
3674
|
-
|
|
3675
|
-
|
|
3837
|
+
removePidFile(config.dataDir);
|
|
3838
|
+
process.exit(1);
|
|
3839
|
+
}
|
|
3840
|
+
if (!json) {
|
|
3841
|
+
console.log(`\u{1F6D1} Stopping node (PID: ${pid})...`);
|
|
3842
|
+
}
|
|
3843
|
+
process.kill(pid, "SIGTERM");
|
|
3844
|
+
let attempts = 0;
|
|
3845
|
+
while (isProcessRunning(pid) && attempts < 30) {
|
|
3846
|
+
await new Promise((resolve2) => setTimeout(resolve2, 100));
|
|
3847
|
+
attempts++;
|
|
3848
|
+
}
|
|
3849
|
+
if (isProcessRunning(pid)) {
|
|
3850
|
+
process.kill(pid, "SIGKILL");
|
|
3851
|
+
}
|
|
3852
|
+
removePidFile(config.dataDir);
|
|
3853
|
+
if (json) {
|
|
3854
|
+
printJsonSuccess({ pid, stopped: true });
|
|
3855
|
+
} else {
|
|
3856
|
+
console.log("\u2705 Node stopped.");
|
|
3857
|
+
}
|
|
3858
|
+
}
|
|
3859
|
+
|
|
3860
|
+
// src/lib/node-upgrade.ts
|
|
3861
|
+
import { BinaryManager as BinaryManager2, MigrationManager as MigrationManager2 } from "@fiber-pay/node";
|
|
3862
|
+
async function runNodeUpgradeCommand(config, options) {
|
|
3863
|
+
const json = Boolean(options.json);
|
|
3864
|
+
const installDir = `${config.dataDir}/bin`;
|
|
3865
|
+
const binaryManager = new BinaryManager2(installDir);
|
|
3866
|
+
const pid = readPidFile(config.dataDir);
|
|
3867
|
+
if (pid && isProcessRunning(pid)) {
|
|
3868
|
+
const msg = "The Fiber node is currently running. Stop it before upgrading.";
|
|
3869
|
+
if (json) {
|
|
3870
|
+
printJsonError({
|
|
3871
|
+
code: "NODE_RUNNING",
|
|
3872
|
+
message: msg,
|
|
3873
|
+
recoverable: true,
|
|
3874
|
+
suggestion: "Run `fiber-pay node stop` first, then retry the upgrade."
|
|
3875
|
+
});
|
|
3876
|
+
} else {
|
|
3877
|
+
console.error(`\u274C ${msg}`);
|
|
3878
|
+
console.log(" Run: fiber-pay node stop");
|
|
3879
|
+
}
|
|
3880
|
+
process.exit(1);
|
|
3881
|
+
}
|
|
3882
|
+
let targetTag;
|
|
3883
|
+
if (options.version) {
|
|
3884
|
+
targetTag = binaryManager.normalizeTag(options.version);
|
|
3885
|
+
} else {
|
|
3886
|
+
if (!json) console.log("\u{1F50D} Resolving latest Fiber release...");
|
|
3887
|
+
targetTag = await binaryManager.getLatestTag();
|
|
3888
|
+
}
|
|
3889
|
+
if (!json) console.log(`\u{1F4E6} Target version: ${targetTag}`);
|
|
3890
|
+
const currentInfo = await binaryManager.getBinaryInfo();
|
|
3891
|
+
const targetVersion = targetTag.startsWith("v") ? targetTag.slice(1) : targetTag;
|
|
3892
|
+
const storePath = MigrationManager2.resolveStorePath(config.dataDir);
|
|
3893
|
+
const migrateBinaryPath = binaryManager.getMigrateBinaryPath();
|
|
3894
|
+
let migrationCheck = null;
|
|
3895
|
+
const storeExists = MigrationManager2.storeExists(config.dataDir);
|
|
3896
|
+
if (!json && storeExists) {
|
|
3897
|
+
console.log("\u{1F4C2} Existing store detected.");
|
|
3898
|
+
}
|
|
3899
|
+
if (currentInfo.ready && currentInfo.version === targetVersion && !options.forceMigrate) {
|
|
3900
|
+
if (storeExists) {
|
|
3901
|
+
migrationCheck = await runMigrationAndReport({
|
|
3902
|
+
migrateBinaryPath,
|
|
3903
|
+
storePath,
|
|
3904
|
+
json,
|
|
3905
|
+
checkOnly: Boolean(options.checkOnly),
|
|
3906
|
+
targetVersion,
|
|
3907
|
+
backup: options.backup !== false,
|
|
3908
|
+
forceMigrateAttempt: false
|
|
3909
|
+
});
|
|
3910
|
+
}
|
|
3911
|
+
const msg = migrationCheck ? `Already installed ${targetTag}. Store compatibility checked.` : `Already installed ${targetTag}. Use --force-migrate to run migration flow anyway.`;
|
|
3912
|
+
if (json) {
|
|
3913
|
+
printJsonSuccess({
|
|
3914
|
+
action: "none",
|
|
3915
|
+
currentVersion: currentInfo.version,
|
|
3916
|
+
targetVersion,
|
|
3917
|
+
message: msg,
|
|
3918
|
+
migration: migrationCheck
|
|
3919
|
+
});
|
|
3920
|
+
} else {
|
|
3921
|
+
console.log(`\u2705 ${msg}`);
|
|
3922
|
+
}
|
|
3923
|
+
return;
|
|
3924
|
+
}
|
|
3925
|
+
const versionMatches = currentInfo.ready && currentInfo.version === targetVersion;
|
|
3926
|
+
const shouldDownload = !versionMatches;
|
|
3927
|
+
if (!json && currentInfo.ready) {
|
|
3928
|
+
console.log(` Current version: v${currentInfo.version}`);
|
|
3929
|
+
}
|
|
3930
|
+
if (shouldDownload) {
|
|
3931
|
+
if (!json && storeExists) {
|
|
3932
|
+
console.log("\u{1F4C2} Existing store detected, will check migration after download.");
|
|
3933
|
+
}
|
|
3934
|
+
if (!json) console.log("\u2B07\uFE0F Downloading new binary...");
|
|
3935
|
+
const showProgress2 = (progress) => {
|
|
3936
|
+
if (!json) {
|
|
3937
|
+
const percent = progress.percent !== void 0 ? ` (${progress.percent}%)` : "";
|
|
3938
|
+
process.stdout.write(`\r [${progress.phase}]${percent} ${progress.message}`.padEnd(80));
|
|
3939
|
+
if (progress.phase === "installing") console.log();
|
|
3676
3940
|
}
|
|
3677
|
-
|
|
3678
|
-
|
|
3941
|
+
};
|
|
3942
|
+
await binaryManager.download({
|
|
3943
|
+
version: targetTag,
|
|
3944
|
+
force: true,
|
|
3945
|
+
onProgress: showProgress2
|
|
3946
|
+
});
|
|
3947
|
+
} else if (!json && options.forceMigrate) {
|
|
3948
|
+
console.log("\u23ED\uFE0F Skipping binary download: target version is already installed.");
|
|
3949
|
+
console.log("\u{1F501} --force-migrate enabled: attempting migration flow on existing binaries.");
|
|
3950
|
+
}
|
|
3951
|
+
if (storeExists) {
|
|
3952
|
+
migrationCheck = await runMigrationAndReport({
|
|
3953
|
+
migrateBinaryPath,
|
|
3954
|
+
storePath,
|
|
3955
|
+
json,
|
|
3956
|
+
checkOnly: Boolean(options.checkOnly),
|
|
3957
|
+
targetVersion,
|
|
3958
|
+
backup: options.backup !== false,
|
|
3959
|
+
forceMigrateAttempt: Boolean(options.forceMigrate)
|
|
3960
|
+
});
|
|
3961
|
+
}
|
|
3962
|
+
const newInfo = await binaryManager.getBinaryInfo();
|
|
3963
|
+
if (json) {
|
|
3964
|
+
printJsonSuccess({
|
|
3965
|
+
action: "upgraded",
|
|
3966
|
+
previousVersion: currentInfo.ready ? currentInfo.version : null,
|
|
3967
|
+
currentVersion: newInfo.version,
|
|
3968
|
+
binaryPath: newInfo.path,
|
|
3969
|
+
migrateBinaryPath,
|
|
3970
|
+
migration: migrationCheck
|
|
3971
|
+
});
|
|
3972
|
+
} else {
|
|
3973
|
+
console.log("\n\u2705 Upgrade complete!");
|
|
3974
|
+
console.log(` Version: v${newInfo.version}`);
|
|
3975
|
+
console.log(` Binary: ${newInfo.path}`);
|
|
3976
|
+
console.log("\n Start the node with: fiber-pay node start");
|
|
3977
|
+
}
|
|
3978
|
+
}
|
|
3979
|
+
async function runMigrationAndReport(opts) {
|
|
3980
|
+
const {
|
|
3981
|
+
migrateBinaryPath,
|
|
3982
|
+
storePath,
|
|
3983
|
+
json,
|
|
3984
|
+
checkOnly,
|
|
3985
|
+
targetVersion,
|
|
3986
|
+
backup,
|
|
3987
|
+
forceMigrateAttempt
|
|
3988
|
+
} = opts;
|
|
3989
|
+
let migrationManager;
|
|
3990
|
+
try {
|
|
3991
|
+
migrationManager = new MigrationManager2(migrateBinaryPath);
|
|
3992
|
+
} catch (err) {
|
|
3993
|
+
const msg = err instanceof Error ? err.message : "fnn-migrate binary not available";
|
|
3994
|
+
if (json) {
|
|
3995
|
+
printJsonError({
|
|
3996
|
+
code: "MIGRATION_TOOL_MISSING",
|
|
3997
|
+
message: msg,
|
|
3998
|
+
recoverable: true,
|
|
3999
|
+
suggestion: "Run `fiber-pay node upgrade` to reinstall binaries, then retry `fiber-pay node upgrade --force-migrate`."
|
|
4000
|
+
});
|
|
4001
|
+
} else {
|
|
4002
|
+
console.error(`
|
|
4003
|
+
\u26A0\uFE0F ${msg}`);
|
|
4004
|
+
console.log(
|
|
4005
|
+
" Run `fiber-pay node upgrade` to reinstall binaries, then retry `fiber-pay node upgrade --force-migrate`."
|
|
4006
|
+
);
|
|
3679
4007
|
}
|
|
3680
|
-
|
|
3681
|
-
|
|
4008
|
+
process.exit(1);
|
|
4009
|
+
}
|
|
4010
|
+
if (!json) console.log("\u{1F50D} Checking store compatibility...");
|
|
4011
|
+
let migrationCheck;
|
|
4012
|
+
try {
|
|
4013
|
+
migrationCheck = await migrationManager.check(storePath);
|
|
4014
|
+
} catch (checkErr) {
|
|
4015
|
+
const msg = checkErr instanceof Error ? checkErr.message : String(checkErr);
|
|
4016
|
+
if (json) {
|
|
4017
|
+
printJsonError({
|
|
4018
|
+
code: "MIGRATION_TOOL_MISSING",
|
|
4019
|
+
message: `Migration check failed: ${msg}`,
|
|
4020
|
+
recoverable: true,
|
|
4021
|
+
suggestion: "Run `fiber-pay node upgrade` to reinstall binaries, then retry `fiber-pay node upgrade --force-migrate`."
|
|
4022
|
+
});
|
|
4023
|
+
} else {
|
|
4024
|
+
console.error(`
|
|
4025
|
+
\u26A0\uFE0F Migration check failed: ${msg}`);
|
|
4026
|
+
console.log(
|
|
4027
|
+
" Run `fiber-pay node upgrade` to reinstall binaries, then retry `fiber-pay node upgrade --force-migrate`."
|
|
4028
|
+
);
|
|
3682
4029
|
}
|
|
3683
|
-
process.
|
|
3684
|
-
|
|
3685
|
-
|
|
3686
|
-
|
|
3687
|
-
|
|
4030
|
+
process.exit(1);
|
|
4031
|
+
}
|
|
4032
|
+
if (checkOnly) {
|
|
4033
|
+
const normalizedCheck = normalizeMigrationCheck(migrationCheck);
|
|
4034
|
+
if (json) {
|
|
4035
|
+
printJsonSuccess({
|
|
4036
|
+
action: "check-only",
|
|
4037
|
+
targetVersion,
|
|
4038
|
+
migration: normalizedCheck
|
|
4039
|
+
});
|
|
4040
|
+
} else {
|
|
4041
|
+
console.log(`
|
|
4042
|
+
\u{1F4CB} Migration status: ${normalizedCheck.message}`);
|
|
3688
4043
|
}
|
|
3689
|
-
|
|
3690
|
-
|
|
4044
|
+
process.exit(0);
|
|
4045
|
+
}
|
|
4046
|
+
if (!migrationCheck.needed) {
|
|
4047
|
+
if (!json) console.log(" Store is compatible, no migration needed.");
|
|
4048
|
+
return normalizeMigrationCheck(migrationCheck);
|
|
4049
|
+
}
|
|
4050
|
+
if (!migrationCheck.valid && !forceMigrateAttempt) {
|
|
4051
|
+
const normalizedMessage = replaceRawMigrateHint(migrationCheck.message);
|
|
4052
|
+
if (json) {
|
|
4053
|
+
printJsonError({
|
|
4054
|
+
code: "MIGRATION_INCOMPATIBLE",
|
|
4055
|
+
message: normalizedMessage,
|
|
4056
|
+
recoverable: false,
|
|
4057
|
+
suggestion: `Back up your store first (directory: "${storePath}"). Then run \`fiber-pay node upgrade --force-migrate\`. If it still fails, close all channels with the old fnn version, remove the store, and restart with a fresh store. If you attempted migration with backup enabled, you can roll back by restoring the backup directory.`,
|
|
4058
|
+
details: {
|
|
4059
|
+
storePath,
|
|
4060
|
+
migrationCheck: {
|
|
4061
|
+
...migrationCheck,
|
|
4062
|
+
message: normalizedMessage
|
|
4063
|
+
}
|
|
4064
|
+
}
|
|
4065
|
+
});
|
|
4066
|
+
} else {
|
|
4067
|
+
console.error("\n\u274C Store migration is not possible automatically.");
|
|
4068
|
+
console.log(normalizedMessage);
|
|
4069
|
+
console.log(` 1) Back up store directory: ${storePath}`);
|
|
4070
|
+
console.log(" 2) Try: fiber-pay node upgrade --force-migrate");
|
|
4071
|
+
console.log(
|
|
4072
|
+
" 3) If it still fails, close channels on old fnn, remove store, then restart."
|
|
4073
|
+
);
|
|
4074
|
+
console.log(" 4) If migration created a backup, you can roll back by restoring it.");
|
|
3691
4075
|
}
|
|
3692
|
-
|
|
4076
|
+
process.exit(1);
|
|
4077
|
+
}
|
|
4078
|
+
if (!migrationCheck.valid && !json) {
|
|
4079
|
+
console.log("\u26A0\uFE0F Store check reported incompatibility, but --force-migrate is set.");
|
|
4080
|
+
console.log(" Attempting migration anyway with backup enabled (unless --no-backup).");
|
|
4081
|
+
}
|
|
4082
|
+
if (!json) console.log("\u{1F504} Running database migration...");
|
|
4083
|
+
const result = await migrationManager.migrate({
|
|
4084
|
+
storePath,
|
|
4085
|
+
backup,
|
|
4086
|
+
force: forceMigrateAttempt
|
|
4087
|
+
});
|
|
4088
|
+
if (!result.success) {
|
|
3693
4089
|
if (json) {
|
|
3694
|
-
|
|
4090
|
+
printJsonError({
|
|
4091
|
+
code: "MIGRATION_FAILED",
|
|
4092
|
+
message: result.message,
|
|
4093
|
+
recoverable: !!result.backupPath,
|
|
4094
|
+
suggestion: result.backupPath ? `To roll back, delete the current store at "${storePath}" and restore the backup from "${result.backupPath}".` : "Re-download the previous version or start fresh.",
|
|
4095
|
+
details: { output: result.output, backupPath: result.backupPath }
|
|
4096
|
+
});
|
|
3695
4097
|
} else {
|
|
3696
|
-
console.
|
|
4098
|
+
console.error("\n\u274C Migration failed.");
|
|
4099
|
+
console.log(result.message);
|
|
3697
4100
|
}
|
|
4101
|
+
process.exit(1);
|
|
4102
|
+
}
|
|
4103
|
+
if (!json) {
|
|
4104
|
+
console.log(`\u2705 ${result.message}`);
|
|
4105
|
+
if (result.backupPath) {
|
|
4106
|
+
console.log(` Backup: ${result.backupPath}`);
|
|
4107
|
+
}
|
|
4108
|
+
}
|
|
4109
|
+
try {
|
|
4110
|
+
const postCheck = await migrationManager.check(storePath);
|
|
4111
|
+
return normalizeMigrationCheck(postCheck);
|
|
4112
|
+
} catch (err) {
|
|
4113
|
+
if (!json) {
|
|
4114
|
+
const message = err instanceof Error ? err.message : String(err);
|
|
4115
|
+
console.error("\u26A0\uFE0F Post-migration check failed; final migration status may be stale.");
|
|
4116
|
+
console.error(` ${message}`);
|
|
4117
|
+
}
|
|
4118
|
+
return normalizeMigrationCheck(migrationCheck);
|
|
4119
|
+
}
|
|
4120
|
+
}
|
|
4121
|
+
|
|
4122
|
+
// src/commands/node.ts
|
|
4123
|
+
function createNodeCommand(config) {
|
|
4124
|
+
const node = new Command8("node").description("Node management");
|
|
4125
|
+
node.command("start").option("--daemon", "Start node in detached background mode (node + runtime)").option("--runtime-proxy-listen <host:port>", "Runtime monitor proxy listen address").option("--event-stream <format>", "Event stream format for --json mode (jsonl)", "jsonl").option("--quiet-fnn", "Do not mirror fnn stdout/stderr to console; keep file persistence").option("--json").action(async (options) => {
|
|
4126
|
+
await runNodeStartCommand(config, options);
|
|
4127
|
+
});
|
|
4128
|
+
node.command("stop").option("--json").action(async (options) => {
|
|
4129
|
+
await runNodeStopCommand(config, options);
|
|
3698
4130
|
});
|
|
3699
4131
|
node.command("status").option("--json").action(async (options) => {
|
|
3700
4132
|
await runNodeStatusCommand(config, options);
|
|
@@ -3725,6 +4157,12 @@ function createNodeCommand(config) {
|
|
|
3725
4157
|
printNodeInfoHuman(output);
|
|
3726
4158
|
}
|
|
3727
4159
|
});
|
|
4160
|
+
node.command("upgrade").description("Upgrade the Fiber node binary and migrate the database if needed").option("--version <version>", "Target Fiber version (default: latest)").option("--no-backup", "Skip creating a store backup before migration").option("--check-only", "Only check if migration is needed, do not migrate").option(
|
|
4161
|
+
"--force-migrate",
|
|
4162
|
+
"Force migration attempt even when compatibility check reports incompatible data"
|
|
4163
|
+
).option("--json").action(async (options) => {
|
|
4164
|
+
await runNodeUpgradeCommand(config, options);
|
|
4165
|
+
});
|
|
3728
4166
|
return node;
|
|
3729
4167
|
}
|
|
3730
4168
|
|
|
@@ -4488,8 +4926,8 @@ function createRuntimeCommand(config) {
|
|
|
4488
4926
|
import { Command as Command12 } from "commander";
|
|
4489
4927
|
|
|
4490
4928
|
// src/lib/build-info.ts
|
|
4491
|
-
var CLI_VERSION = "0.1.0-rc.
|
|
4492
|
-
var CLI_COMMIT = "
|
|
4929
|
+
var CLI_VERSION = "0.1.0-rc.4";
|
|
4930
|
+
var CLI_COMMIT = "20dc82d290856d411382a4ec30f912b913b4f956";
|
|
4493
4931
|
|
|
4494
4932
|
// src/commands/version.ts
|
|
4495
4933
|
function createVersionCommand() {
|
|
@@ -4507,6 +4945,55 @@ function createVersionCommand() {
|
|
|
4507
4945
|
});
|
|
4508
4946
|
}
|
|
4509
4947
|
|
|
4948
|
+
// src/lib/argv.ts
|
|
4949
|
+
var GLOBAL_OPTIONS_WITH_VALUE = /* @__PURE__ */ new Set([
|
|
4950
|
+
"--profile",
|
|
4951
|
+
"--data-dir",
|
|
4952
|
+
"--rpc-url",
|
|
4953
|
+
"--network",
|
|
4954
|
+
"--key-password",
|
|
4955
|
+
"--binary-path"
|
|
4956
|
+
]);
|
|
4957
|
+
function isOptionToken(token) {
|
|
4958
|
+
return token.startsWith("-") && token !== "-";
|
|
4959
|
+
}
|
|
4960
|
+
function hasInlineValue(token) {
|
|
4961
|
+
return token.includes("=");
|
|
4962
|
+
}
|
|
4963
|
+
function getFirstPositional(argv) {
|
|
4964
|
+
for (let index = 2; index < argv.length; index++) {
|
|
4965
|
+
const token = argv[index];
|
|
4966
|
+
if (token === "--") {
|
|
4967
|
+
return argv[index + 1];
|
|
4968
|
+
}
|
|
4969
|
+
if (!isOptionToken(token)) {
|
|
4970
|
+
return token;
|
|
4971
|
+
}
|
|
4972
|
+
if (GLOBAL_OPTIONS_WITH_VALUE.has(token) && !hasInlineValue(token)) {
|
|
4973
|
+
const next = argv[index + 1];
|
|
4974
|
+
if (next && !isOptionToken(next)) {
|
|
4975
|
+
index++;
|
|
4976
|
+
}
|
|
4977
|
+
}
|
|
4978
|
+
}
|
|
4979
|
+
return void 0;
|
|
4980
|
+
}
|
|
4981
|
+
function hasTopLevelVersionFlag(argv) {
|
|
4982
|
+
for (let index = 2; index < argv.length; index++) {
|
|
4983
|
+
const token = argv[index];
|
|
4984
|
+
if (token === "--") {
|
|
4985
|
+
return false;
|
|
4986
|
+
}
|
|
4987
|
+
if (token === "--version" || token === "-v") {
|
|
4988
|
+
return true;
|
|
4989
|
+
}
|
|
4990
|
+
}
|
|
4991
|
+
return false;
|
|
4992
|
+
}
|
|
4993
|
+
function isTopLevelVersionRequest(argv) {
|
|
4994
|
+
return !getFirstPositional(argv) && hasTopLevelVersionFlag(argv);
|
|
4995
|
+
}
|
|
4996
|
+
|
|
4510
4997
|
// src/index.ts
|
|
4511
4998
|
function shouldOutputJson() {
|
|
4512
4999
|
return process.argv.includes("--json");
|
|
@@ -4608,10 +5095,15 @@ function printFatal(error) {
|
|
|
4608
5095
|
}
|
|
4609
5096
|
}
|
|
4610
5097
|
async function main() {
|
|
4611
|
-
|
|
5098
|
+
const argv = process.argv;
|
|
5099
|
+
if (isTopLevelVersionRequest(argv)) {
|
|
5100
|
+
console.log(`${CLI_VERSION} (${CLI_COMMIT})`);
|
|
5101
|
+
return;
|
|
5102
|
+
}
|
|
5103
|
+
applyGlobalOverrides(argv);
|
|
4612
5104
|
const config = getEffectiveConfig(explicitFlags).config;
|
|
4613
5105
|
const program = new Command13();
|
|
4614
|
-
program.name("fiber-pay").description("AI Agent Payment SDK for CKB Lightning Network").
|
|
5106
|
+
program.name("fiber-pay").description("AI Agent Payment SDK for CKB Lightning Network").option("--profile <name>", "Use profile at ~/.fiber-pay/profiles/<name>").option("--data-dir <path>", "Override data directory for all commands").option("--rpc-url <url>", "Override RPC URL for all commands").option("--network <network>", "Override network for all commands (testnet|mainnet)").option("--key-password <password>", "Override key password for all commands").option("--binary-path <path>", "Override fiber binary path for all commands").showHelpAfterError().showSuggestionAfterError();
|
|
4615
5107
|
program.exitOverride();
|
|
4616
5108
|
program.configureOutput({
|
|
4617
5109
|
writeOut: (str) => process.stdout.write(str),
|
|
@@ -4633,7 +5125,7 @@ async function main() {
|
|
|
4633
5125
|
program.addCommand(createConfigCommand(config));
|
|
4634
5126
|
program.addCommand(createRuntimeCommand(config));
|
|
4635
5127
|
program.addCommand(createVersionCommand());
|
|
4636
|
-
await program.parseAsync(
|
|
5128
|
+
await program.parseAsync(argv);
|
|
4637
5129
|
}
|
|
4638
5130
|
main().catch((error) => {
|
|
4639
5131
|
const commanderCode = error && typeof error === "object" && "code" in error ? String(error.code) : void 0;
|