polycopy 0.0.9 → 0.1.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/cli.js
CHANGED
|
@@ -3,7 +3,7 @@
|
|
|
3
3
|
const child_process = require("child_process");
|
|
4
4
|
const fs = require("fs");
|
|
5
5
|
const path = require("path");
|
|
6
|
-
const paths = require("./paths-
|
|
6
|
+
const paths = require("./paths-CEjGES8j.js");
|
|
7
7
|
function _interopNamespace(e) {
|
|
8
8
|
if (e && e.__esModule) return e;
|
|
9
9
|
const n = Object.create(null, { [Symbol.toStringTag]: { value: "Module" } });
|
|
@@ -35,6 +35,10 @@ function getRunningPid() {
|
|
|
35
35
|
try {
|
|
36
36
|
const pid = parseInt(fs__namespace.readFileSync(paths.PID_FILE, "utf-8").trim());
|
|
37
37
|
process.kill(pid, 0);
|
|
38
|
+
if (!isPolycopyProcess(pid)) {
|
|
39
|
+
fs__namespace.unlinkSync(paths.PID_FILE);
|
|
40
|
+
return null;
|
|
41
|
+
}
|
|
38
42
|
return pid;
|
|
39
43
|
} catch {
|
|
40
44
|
fs__namespace.unlinkSync(paths.PID_FILE);
|
|
@@ -111,10 +115,65 @@ async function startDaemon() {
|
|
|
111
115
|
const mainPath = path__namespace.join(__dirname, "index.js");
|
|
112
116
|
await import(mainPath);
|
|
113
117
|
}
|
|
118
|
+
function isPolycopyProcess(pid) {
|
|
119
|
+
if (process.platform === "win32") {
|
|
120
|
+
return true;
|
|
121
|
+
}
|
|
122
|
+
const result = child_process.spawnSync("ps", ["-p", String(pid), "-o", "command="], {
|
|
123
|
+
encoding: "utf-8"
|
|
124
|
+
});
|
|
125
|
+
if (result.status !== 0) {
|
|
126
|
+
return false;
|
|
127
|
+
}
|
|
128
|
+
const command = result.stdout.trim();
|
|
129
|
+
if (!command) {
|
|
130
|
+
return false;
|
|
131
|
+
}
|
|
132
|
+
return command.includes(paths.DIST_INDEX) || command.includes(paths.DIST_CLI);
|
|
133
|
+
}
|
|
134
|
+
function findPolycopyPids() {
|
|
135
|
+
if (process.platform === "win32") {
|
|
136
|
+
return [];
|
|
137
|
+
}
|
|
138
|
+
const result = child_process.spawnSync("ps", ["-ax", "-o", "pid=,command="], {
|
|
139
|
+
encoding: "utf-8"
|
|
140
|
+
});
|
|
141
|
+
if (result.status !== 0) {
|
|
142
|
+
return [];
|
|
143
|
+
}
|
|
144
|
+
return result.stdout.split("\n").map((line) => line.trim()).filter(Boolean).map((line) => {
|
|
145
|
+
const firstSpace = line.indexOf(" ");
|
|
146
|
+
if (firstSpace === -1) return null;
|
|
147
|
+
const pidText = line.slice(0, firstSpace).trim();
|
|
148
|
+
const command = line.slice(firstSpace + 1).trim();
|
|
149
|
+
const pid = parseInt(pidText, 10);
|
|
150
|
+
if (Number.isNaN(pid)) return null;
|
|
151
|
+
if (pid === process.pid) return null;
|
|
152
|
+
if (!(command.includes(paths.DIST_INDEX) || command.includes(paths.DIST_CLI))) {
|
|
153
|
+
return null;
|
|
154
|
+
}
|
|
155
|
+
return pid;
|
|
156
|
+
}).filter((pid) => pid !== null);
|
|
157
|
+
}
|
|
114
158
|
function stopDaemon() {
|
|
115
159
|
const pid = getRunningPid();
|
|
116
160
|
if (!pid) {
|
|
117
|
-
|
|
161
|
+
const fallbackPids = findPolycopyPids();
|
|
162
|
+
if (fallbackPids.length === 0) {
|
|
163
|
+
console.log("ℹ️ 没有运行中的前台/后台进程");
|
|
164
|
+
return;
|
|
165
|
+
}
|
|
166
|
+
console.log(
|
|
167
|
+
`⚠️ 未找到 PID 文件,尝试停止前台/后台进程 (${fallbackPids.length} 个)`
|
|
168
|
+
);
|
|
169
|
+
fallbackPids.forEach((fallbackPid) => {
|
|
170
|
+
try {
|
|
171
|
+
process.kill(fallbackPid, "SIGTERM");
|
|
172
|
+
console.log(`✅ 已发送停止信号 (PID: ${fallbackPid})`);
|
|
173
|
+
} catch (error) {
|
|
174
|
+
console.error(`❌ 停止失败 (PID: ${fallbackPid}):`, error);
|
|
175
|
+
}
|
|
176
|
+
});
|
|
118
177
|
return;
|
|
119
178
|
}
|
|
120
179
|
try {
|
package/dist/config.js
CHANGED
package/dist/index.js
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
"use strict";
|
|
2
|
-
const init = require("./init-
|
|
2
|
+
const init = require("./init-OIFlNHFx.js");
|
|
3
3
|
const grammy = require("grammy");
|
|
4
4
|
const wallet = require("@ethersproject/wallet");
|
|
5
5
|
const clobClient = require("@polymarket/clob-client");
|
|
@@ -11,7 +11,7 @@ const builderRelayerClient = require("@polymarket/builder-relayer-client");
|
|
|
11
11
|
const setPromiseInterval = require("set-promise-interval");
|
|
12
12
|
const child_process = require("child_process");
|
|
13
13
|
const fs = require("fs");
|
|
14
|
-
const paths = require("./paths-
|
|
14
|
+
const paths = require("./paths-CEjGES8j.js");
|
|
15
15
|
const _interopDefault = (e) => e && e.__esModule ? e : { default: e };
|
|
16
16
|
function _interopNamespace(e) {
|
|
17
17
|
if (e && e.__esModule) return e;
|
|
@@ -175,14 +175,14 @@ class ClobClientWrapper {
|
|
|
175
175
|
*/
|
|
176
176
|
async getTickSize(tokenId) {
|
|
177
177
|
const client = this.ensureInitialized();
|
|
178
|
-
return
|
|
178
|
+
return client.getTickSize(tokenId);
|
|
179
179
|
}
|
|
180
180
|
/**
|
|
181
181
|
* 获取 token 是否为 negRisk
|
|
182
182
|
*/
|
|
183
183
|
async getNegRisk(tokenId) {
|
|
184
184
|
const client = this.ensureInitialized();
|
|
185
|
-
return
|
|
185
|
+
return client.getNegRisk(tokenId);
|
|
186
186
|
}
|
|
187
187
|
/**
|
|
188
188
|
* 创建买单(GTC 限价单)
|
|
@@ -272,7 +272,7 @@ class ClobClientWrapper {
|
|
|
272
272
|
*/
|
|
273
273
|
async getOrder(orderId) {
|
|
274
274
|
const client = this.ensureInitialized();
|
|
275
|
-
return
|
|
275
|
+
return client.getOrder(orderId);
|
|
276
276
|
}
|
|
277
277
|
/**
|
|
278
278
|
* 取消订单
|
|
@@ -723,7 +723,7 @@ conditionId: ${position.conditionId}
|
|
|
723
723
|
}
|
|
724
724
|
this.onRedeemSuccess?.();
|
|
725
725
|
}
|
|
726
|
-
init.logger.info(`
|
|
726
|
+
init.logger.info(`redeem 记录: ${this.records.size} 个待确认`);
|
|
727
727
|
}
|
|
728
728
|
/**
|
|
729
729
|
* 解析 429 错误中的 resets in 时间
|
|
@@ -1003,7 +1003,7 @@ class Trader {
|
|
|
1003
1003
|
if (!this.relayClient.isInitialized()) {
|
|
1004
1004
|
throw new Error("RelayClient 未初始化");
|
|
1005
1005
|
}
|
|
1006
|
-
return
|
|
1006
|
+
return this.relayClient.redeem(conditionId);
|
|
1007
1007
|
}
|
|
1008
1008
|
/**
|
|
1009
1009
|
* 停止交易模块
|
|
@@ -1021,7 +1021,11 @@ function enterDaemonMode() {
|
|
|
1021
1021
|
const child = child_process.spawn(process.execPath, [__filename], {
|
|
1022
1022
|
detached: true,
|
|
1023
1023
|
stdio: "ignore",
|
|
1024
|
-
env: {
|
|
1024
|
+
env: {
|
|
1025
|
+
...process.env,
|
|
1026
|
+
POLYCOPY_DAEMON: void 0,
|
|
1027
|
+
POLYCOPY_DAEMON_CHILD: "1"
|
|
1028
|
+
}
|
|
1025
1029
|
});
|
|
1026
1030
|
if (child.pid) {
|
|
1027
1031
|
fs__namespace.writeFileSync(paths.PID_FILE, child.pid.toString());
|
|
@@ -1075,7 +1079,7 @@ async function main() {
|
|
|
1075
1079
|
config.telegram.botToken,
|
|
1076
1080
|
config.telegram.targetChatIds || []
|
|
1077
1081
|
);
|
|
1078
|
-
listener.onChatIdsChanged(
|
|
1082
|
+
listener.onChatIdsChanged((chatIds) => {
|
|
1079
1083
|
const telegram = init.configLocal.getItem("telegram");
|
|
1080
1084
|
if (!telegram) {
|
|
1081
1085
|
init.logger.error("警告: 无法保存频道 ID,telegram 配置不存在");
|
|
@@ -1106,6 +1110,13 @@ async function main() {
|
|
|
1106
1110
|
}
|
|
1107
1111
|
}
|
|
1108
1112
|
});
|
|
1113
|
+
if (process.env.POLYCOPY_DAEMON === "1") {
|
|
1114
|
+
enterDaemonMode();
|
|
1115
|
+
return;
|
|
1116
|
+
}
|
|
1117
|
+
const runMode = process.env.POLYCOPY_DAEMON_CHILD === "1" ? "后台模式" : "前台模式";
|
|
1118
|
+
notifier.success("程序已启动", `模式: ${runMode}
|
|
1119
|
+
PID: ${process.pid}`);
|
|
1109
1120
|
let isShuttingDown = false;
|
|
1110
1121
|
const shutdown = () => {
|
|
1111
1122
|
if (isShuttingDown) return;
|
|
@@ -1114,6 +1125,8 @@ async function main() {
|
|
|
1114
1125
|
process.removeAllListeners("SIGTERM");
|
|
1115
1126
|
init.logger.blank();
|
|
1116
1127
|
init.logger.info("正在退出...");
|
|
1128
|
+
notifier.warning("程序已停止", `模式: ${runMode}
|
|
1129
|
+
PID: ${process.pid}`);
|
|
1117
1130
|
setTimeout(() => {
|
|
1118
1131
|
process.exit(0);
|
|
1119
1132
|
}, 1e3);
|
|
@@ -1123,10 +1136,6 @@ async function main() {
|
|
|
1123
1136
|
};
|
|
1124
1137
|
process.on("SIGINT", shutdown);
|
|
1125
1138
|
process.on("SIGTERM", shutdown);
|
|
1126
|
-
if (process.env.POLYCOPY_DAEMON === "1") {
|
|
1127
|
-
enterDaemonMode();
|
|
1128
|
-
return;
|
|
1129
|
-
}
|
|
1130
1139
|
await listener.start(() => {
|
|
1131
1140
|
if (trader.isInitialized()) {
|
|
1132
1141
|
trader.startRedeemer();
|
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
const readline = require("readline");
|
|
3
3
|
const fsExtra = require("fs-extra");
|
|
4
4
|
const path = require("path");
|
|
5
|
-
const paths = require("./paths-
|
|
5
|
+
const paths = require("./paths-CEjGES8j.js");
|
|
6
6
|
const grammy = require("grammy");
|
|
7
7
|
const winston = require("winston");
|
|
8
8
|
const DailyRotateFile = require("winston-daily-rotate-file");
|
|
@@ -578,7 +578,7 @@ class TelegramListener {
|
|
|
578
578
|
*/
|
|
579
579
|
async getBotInfo() {
|
|
580
580
|
try {
|
|
581
|
-
return
|
|
581
|
+
return this.bot.api.getMe();
|
|
582
582
|
} catch (error) {
|
|
583
583
|
throw new Error(`获取 Bot 信息失败: ${error}`);
|
|
584
584
|
}
|
|
@@ -776,7 +776,7 @@ async function runConfigWizard(existingConfig) {
|
|
|
776
776
|
return config;
|
|
777
777
|
}
|
|
778
778
|
async function initConfig() {
|
|
779
|
-
return
|
|
779
|
+
return runConfigWizard();
|
|
780
780
|
}
|
|
781
781
|
async function configureTrading(existingConfig) {
|
|
782
782
|
logger.section("交易配置");
|
|
@@ -917,7 +917,7 @@ async function ensureConfig() {
|
|
|
917
917
|
const trading = configLocal.getItem("trading");
|
|
918
918
|
if (!telegram && !polymarket && !trading) {
|
|
919
919
|
logger.info("未找到配置文件,开始初始化配置...");
|
|
920
|
-
return
|
|
920
|
+
return initConfig();
|
|
921
921
|
}
|
|
922
922
|
const config = {
|
|
923
923
|
telegram: telegram || { botToken: "" },
|
|
@@ -929,7 +929,7 @@ async function ensureConfig() {
|
|
|
929
929
|
logger.warning("配置文件不完整,缺少以下字段:");
|
|
930
930
|
validation.missingFields.forEach((field) => logger.item(`- ${field}`, 1));
|
|
931
931
|
logger.info("开始重新配置...");
|
|
932
|
-
return
|
|
932
|
+
return initConfig();
|
|
933
933
|
}
|
|
934
934
|
if (!hasPolyMarketConfig(config)) {
|
|
935
935
|
logger.info("未检测到 PolyMarket 配置");
|
|
@@ -937,7 +937,7 @@ async function ensureConfig() {
|
|
|
937
937
|
"是否要运行完整配置向导?(y/n,默认 n,选择 n 将跳过配置): "
|
|
938
938
|
);
|
|
939
939
|
if (useFullWizard.trim().toLowerCase() === "y") {
|
|
940
|
-
return
|
|
940
|
+
return runConfigWizard(config);
|
|
941
941
|
} else {
|
|
942
942
|
logger.info("ℹ️ 已跳过 PolyMarket 配置");
|
|
943
943
|
}
|
|
@@ -9,6 +9,11 @@ const PID_DIR = USER_DATA_DIR;
|
|
|
9
9
|
const LOGS_DIR = path__default.default.join(USER_DATA_DIR, "logs");
|
|
10
10
|
const LOCALSTORAGE_DIR = path__default.default.join(USER_DATA_DIR, "localstorage");
|
|
11
11
|
const PID_FILE = path__default.default.join(USER_DATA_DIR, "polycopy.pid");
|
|
12
|
+
const INSTALL_ROOT = path__default.default.resolve(__dirname, "..");
|
|
13
|
+
const DIST_INDEX = path__default.default.join(INSTALL_ROOT, "dist", "index.js");
|
|
14
|
+
const DIST_CLI = path__default.default.join(INSTALL_ROOT, "dist", "cli.js");
|
|
15
|
+
exports.DIST_CLI = DIST_CLI;
|
|
16
|
+
exports.DIST_INDEX = DIST_INDEX;
|
|
12
17
|
exports.LOCALSTORAGE_DIR = LOCALSTORAGE_DIR;
|
|
13
18
|
exports.LOGS_DIR = LOGS_DIR;
|
|
14
19
|
exports.PID_DIR = PID_DIR;
|