@ape-church/skill 1.0.3 ā 1.0.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/bin/cli.js +351 -149
- package/package.json +1 -1
package/bin/cli.js
CHANGED
|
@@ -414,7 +414,7 @@ function getStrategyConfig(strategy) {
|
|
|
414
414
|
);
|
|
415
415
|
const configs = {
|
|
416
416
|
conservative: {
|
|
417
|
-
minBetApe:
|
|
417
|
+
minBetApe: 1,
|
|
418
418
|
targetBetPct: 0.05,
|
|
419
419
|
maxBetPct: 0.1,
|
|
420
420
|
baseCooldownMs: 60 * 1000, // 60 seconds
|
|
@@ -423,7 +423,7 @@ function getStrategyConfig(strategy) {
|
|
|
423
423
|
gameWeights: defaultWeights,
|
|
424
424
|
},
|
|
425
425
|
balanced: {
|
|
426
|
-
minBetApe:
|
|
426
|
+
minBetApe: 1,
|
|
427
427
|
targetBetPct: 0.08,
|
|
428
428
|
maxBetPct: 0.15,
|
|
429
429
|
baseCooldownMs: 30 * 1000, // 30 seconds
|
|
@@ -432,7 +432,7 @@ function getStrategyConfig(strategy) {
|
|
|
432
432
|
gameWeights: defaultWeights,
|
|
433
433
|
},
|
|
434
434
|
aggressive: {
|
|
435
|
-
minBetApe:
|
|
435
|
+
minBetApe: 1,
|
|
436
436
|
targetBetPct: 0.12,
|
|
437
437
|
maxBetPct: 0.25,
|
|
438
438
|
baseCooldownMs: 15 * 1000, // 15 seconds
|
|
@@ -441,7 +441,7 @@ function getStrategyConfig(strategy) {
|
|
|
441
441
|
gameWeights: defaultWeights,
|
|
442
442
|
},
|
|
443
443
|
degen: {
|
|
444
|
-
minBetApe:
|
|
444
|
+
minBetApe: 1,
|
|
445
445
|
targetBetPct: 0.2,
|
|
446
446
|
maxBetPct: 0.35,
|
|
447
447
|
baseCooldownMs: 10 * 1000, // 10 seconds
|
|
@@ -856,25 +856,37 @@ program
|
|
|
856
856
|
console.log('You can retry later with: apechurch register --username <NAME>');
|
|
857
857
|
}
|
|
858
858
|
|
|
859
|
-
// 4. The Handshake
|
|
859
|
+
// 4. The Handshake
|
|
860
860
|
console.log('\nSETUP COMPLETE');
|
|
861
861
|
console.log('---------------------------------------');
|
|
862
862
|
console.log(`AGENT ADDRESS: ${address}`);
|
|
863
863
|
console.log(`USERNAME: ${username}`);
|
|
864
|
-
if (!usernameWasProvided) {
|
|
865
|
-
console.log(' (Change anytime: apechurch register --username <YOUR_NAME>)');
|
|
866
|
-
}
|
|
867
864
|
console.log(`PERSONA: ${persona}`);
|
|
868
865
|
console.log('');
|
|
869
|
-
console.log('
|
|
870
|
-
console.log('
|
|
871
|
-
console.log(
|
|
872
|
-
|
|
873
|
-
);
|
|
874
|
-
console.log('
|
|
875
|
-
console.log('
|
|
876
|
-
console.log('
|
|
877
|
-
console.log('
|
|
866
|
+
console.log('Change username anytime: apechurch register --username <YOUR_NAME>');
|
|
867
|
+
console.log('');
|
|
868
|
+
console.log('STEP 1: Fund your agent');
|
|
869
|
+
console.log(' Send APE (on ApeChain) to the address above.');
|
|
870
|
+
console.log(' Bridge: https://relay.link/bridge/apechain');
|
|
871
|
+
console.log('');
|
|
872
|
+
console.log('STEP 2: Start playing');
|
|
873
|
+
console.log(' Check balance: apechurch status');
|
|
874
|
+
console.log(' Single bet: apechurch heartbeat --strategy balanced');
|
|
875
|
+
console.log(' Continuous play: apechurch heartbeat --strategy balanced --loop');
|
|
876
|
+
console.log('');
|
|
877
|
+
console.log('AVAILABLE GAMES:');
|
|
878
|
+
console.log(' Jungle Plinko: apechurch bet --game jungle-plinko --amount 5 --mode 2 --balls 50');
|
|
879
|
+
console.log(' Dino Dough: apechurch bet --game dino-dough --amount 5 --spins 10');
|
|
880
|
+
console.log(' Bubblegum Heist: apechurch bet --game bubblegum-heist --amount 5 --spins 8');
|
|
881
|
+
console.log('');
|
|
882
|
+
console.log('STEP 3: Control');
|
|
883
|
+
console.log(' Pause anytime: apechurch pause');
|
|
884
|
+
console.log(' Resume play: apechurch resume');
|
|
885
|
+
console.log(' Stop loop: Ctrl+C');
|
|
886
|
+
console.log('');
|
|
887
|
+
console.log('HELP:');
|
|
888
|
+
console.log(' List all games: apechurch games');
|
|
889
|
+
console.log(' List all commands: apechurch commands');
|
|
878
890
|
console.log('---------------------------------------');
|
|
879
891
|
});
|
|
880
892
|
|
|
@@ -1083,163 +1095,353 @@ program
|
|
|
1083
1095
|
// --- COMMAND: HEARTBEAT (Autonomous Loop) ---
|
|
1084
1096
|
program
|
|
1085
1097
|
.command('heartbeat')
|
|
1086
|
-
.option('--strategy <name>', 'conservative | balanced | aggressive')
|
|
1098
|
+
.option('--strategy <name>', 'conservative | balanced | aggressive | degen')
|
|
1087
1099
|
.option('--cooldown <ms>', 'Minimum ms between plays (0 = use strategy cooldown)', '0')
|
|
1088
1100
|
.option('--timeout <ms>', 'Max ms to wait for GameEnded event. Use 0 to wait indefinitely.', '0')
|
|
1101
|
+
.option('--loop', 'Run continuously until paused or stopped (Ctrl+C)')
|
|
1089
1102
|
.option('--json', 'Output JSON only')
|
|
1090
1103
|
.action(async (opts) => {
|
|
1091
1104
|
const account = getWallet();
|
|
1092
|
-
const state = loadState();
|
|
1093
|
-
const profile = loadProfile();
|
|
1094
|
-
const now = Date.now();
|
|
1095
|
-
|
|
1096
|
-
// Check if paused - skip gracefully without fetching balance
|
|
1097
|
-
if (profile.paused) {
|
|
1098
|
-
state.lastHeartbeat = now;
|
|
1099
|
-
saveState(state);
|
|
1100
|
-
const response = {
|
|
1101
|
-
action: 'heartbeat',
|
|
1102
|
-
status: 'skipped',
|
|
1103
|
-
reason: 'paused',
|
|
1104
|
-
message: 'Autonomous play is paused. Run `apechurch resume` to continue.',
|
|
1105
|
-
address: account.address,
|
|
1106
|
-
paused: true,
|
|
1107
|
-
};
|
|
1108
|
-
if (opts.json) console.log(JSON.stringify(response));
|
|
1109
|
-
else console.log(JSON.stringify(response, null, 2));
|
|
1110
|
-
return;
|
|
1111
|
-
}
|
|
1112
|
-
|
|
1113
|
-
state.lastHeartbeat = now;
|
|
1114
|
-
if (opts.strategy) state.strategy = normalizeStrategy(opts.strategy);
|
|
1115
|
-
else if (profile.persona) state.strategy = normalizeStrategy(profile.persona);
|
|
1116
1105
|
const requestedCooldown = parseNonNegativeInt(opts.cooldown, 'cooldown');
|
|
1117
|
-
if (requestedCooldown > 0) state.cooldownMs = requestedCooldown;
|
|
1118
1106
|
const timeoutMs = parseNonNegativeInt(opts.timeout, 'timeout');
|
|
1107
|
+
const loopMode = Boolean(opts.loop);
|
|
1119
1108
|
|
|
1120
|
-
|
|
1121
|
-
|
|
1122
|
-
try {
|
|
1123
|
-
balance = await publicClient.getBalance({ address: account.address });
|
|
1124
|
-
} catch (error) {
|
|
1125
|
-
console.error(JSON.stringify({ error: `Failed to fetch balance: ${sanitizeError(error)}` }));
|
|
1126
|
-
process.exit(1);
|
|
1109
|
+
if (loopMode && !opts.json) {
|
|
1110
|
+
console.log('š° Starting continuous play mode (Ctrl+C to stop)...\n');
|
|
1127
1111
|
}
|
|
1128
1112
|
|
|
1129
|
-
|
|
1130
|
-
|
|
1131
|
-
|
|
1132
|
-
|
|
1133
|
-
|
|
1134
|
-
|
|
1135
|
-
|
|
1136
|
-
|
|
1137
|
-
|
|
1138
|
-
|
|
1113
|
+
// Main play function - returns cooldown to wait (0 = no wait needed)
|
|
1114
|
+
async function runHeartbeat() {
|
|
1115
|
+
const state = loadState();
|
|
1116
|
+
const profile = loadProfile();
|
|
1117
|
+
const now = Date.now();
|
|
1118
|
+
|
|
1119
|
+
// Check if paused
|
|
1120
|
+
if (profile.paused) {
|
|
1121
|
+
state.lastHeartbeat = now;
|
|
1122
|
+
saveState(state);
|
|
1123
|
+
const response = {
|
|
1124
|
+
action: 'heartbeat',
|
|
1125
|
+
status: 'skipped',
|
|
1126
|
+
reason: 'paused',
|
|
1127
|
+
message: 'Autonomous play is paused. Run `apechurch resume` to continue.',
|
|
1128
|
+
address: account.address,
|
|
1129
|
+
paused: true,
|
|
1130
|
+
};
|
|
1131
|
+
if (opts.json) console.log(JSON.stringify(response));
|
|
1132
|
+
else console.log(JSON.stringify(response, null, 2));
|
|
1133
|
+
return { shouldStop: true, waitMs: 0 };
|
|
1134
|
+
}
|
|
1139
1135
|
|
|
1140
|
-
|
|
1141
|
-
|
|
1142
|
-
strategy
|
|
1143
|
-
|
|
1144
|
-
|
|
1145
|
-
|
|
1146
|
-
|
|
1147
|
-
|
|
1148
|
-
|
|
1149
|
-
|
|
1150
|
-
|
|
1151
|
-
|
|
1152
|
-
|
|
1136
|
+
state.lastHeartbeat = now;
|
|
1137
|
+
if (opts.strategy) state.strategy = normalizeStrategy(opts.strategy);
|
|
1138
|
+
else if (profile.persona) state.strategy = normalizeStrategy(profile.persona);
|
|
1139
|
+
if (requestedCooldown > 0) state.cooldownMs = requestedCooldown;
|
|
1140
|
+
|
|
1141
|
+
const { publicClient } = createClients();
|
|
1142
|
+
let balance;
|
|
1143
|
+
try {
|
|
1144
|
+
balance = await publicClient.getBalance({ address: account.address });
|
|
1145
|
+
} catch (error) {
|
|
1146
|
+
console.error(JSON.stringify({ error: `Failed to fetch balance: ${sanitizeError(error)}` }));
|
|
1147
|
+
return { shouldStop: true, waitMs: 0 };
|
|
1148
|
+
}
|
|
1153
1149
|
|
|
1154
|
-
|
|
1155
|
-
|
|
1156
|
-
const
|
|
1157
|
-
|
|
1158
|
-
|
|
1159
|
-
|
|
1150
|
+
const balanceApe = parseFloat(formatEther(balance));
|
|
1151
|
+
const availableApe = Math.max(balanceApe - GAS_RESERVE_APE, 0);
|
|
1152
|
+
const strategy = normalizeStrategy(state.strategy);
|
|
1153
|
+
const strategyConfig = applyProfileOverrides(
|
|
1154
|
+
getStrategyConfig(strategy),
|
|
1155
|
+
profile.overrides
|
|
1156
|
+
);
|
|
1157
|
+
const dynamicCooldownMs = computeCooldownMs(strategyConfig, state);
|
|
1158
|
+
const cooldownMs = requestedCooldown > 0 ? requestedCooldown : dynamicCooldownMs;
|
|
1159
|
+
|
|
1160
|
+
const baseResponse = {
|
|
1161
|
+
action: 'heartbeat',
|
|
1162
|
+
strategy,
|
|
1163
|
+
address: account.address,
|
|
1164
|
+
balance_ape: balanceApe.toFixed(6),
|
|
1165
|
+
available_ape: availableApe.toFixed(6),
|
|
1166
|
+
gas_reserve_ape: GAS_RESERVE_APE.toFixed(6),
|
|
1167
|
+
paused: false,
|
|
1168
|
+
last_play: state.lastPlay,
|
|
1169
|
+
cooldown_ms: cooldownMs,
|
|
1170
|
+
consecutive_wins: state.consecutiveWins,
|
|
1171
|
+
consecutive_losses: state.consecutiveLosses,
|
|
1160
1172
|
};
|
|
1161
|
-
if (opts.json) console.log(JSON.stringify(response));
|
|
1162
|
-
else console.log(JSON.stringify(response, null, 2));
|
|
1163
|
-
return;
|
|
1164
|
-
}
|
|
1165
1173
|
|
|
1166
|
-
|
|
1167
|
-
|
|
1168
|
-
|
|
1169
|
-
|
|
1170
|
-
|
|
1171
|
-
|
|
1172
|
-
|
|
1173
|
-
|
|
1174
|
-
|
|
1175
|
-
|
|
1176
|
-
|
|
1177
|
-
}
|
|
1174
|
+
if (availableApe <= 0 || availableApe < strategyConfig.minBetApe) {
|
|
1175
|
+
saveState(state);
|
|
1176
|
+
const response = {
|
|
1177
|
+
...baseResponse,
|
|
1178
|
+
status: 'skipped',
|
|
1179
|
+
reason: 'insufficient_available_ape',
|
|
1180
|
+
};
|
|
1181
|
+
if (opts.json) console.log(JSON.stringify(response));
|
|
1182
|
+
else console.log(JSON.stringify(response, null, 2));
|
|
1183
|
+
return { shouldStop: true, waitMs: 0 };
|
|
1184
|
+
}
|
|
1178
1185
|
|
|
1179
|
-
|
|
1180
|
-
|
|
1181
|
-
|
|
1182
|
-
|
|
1183
|
-
|
|
1184
|
-
|
|
1185
|
-
|
|
1186
|
-
|
|
1187
|
-
|
|
1188
|
-
|
|
1189
|
-
|
|
1190
|
-
|
|
1191
|
-
|
|
1186
|
+
if (state.lastPlay && cooldownMs > 0 && now - state.lastPlay < cooldownMs) {
|
|
1187
|
+
const waitMs = Math.max(cooldownMs - (now - state.lastPlay), 0);
|
|
1188
|
+
saveState(state);
|
|
1189
|
+
const response = {
|
|
1190
|
+
...baseResponse,
|
|
1191
|
+
status: 'skipped',
|
|
1192
|
+
reason: 'cooldown',
|
|
1193
|
+
next_play_after_ms: waitMs,
|
|
1194
|
+
};
|
|
1195
|
+
if (opts.json) console.log(JSON.stringify(response));
|
|
1196
|
+
else console.log(JSON.stringify(response, null, 2));
|
|
1197
|
+
return { shouldStop: false, waitMs };
|
|
1198
|
+
}
|
|
1192
1199
|
|
|
1193
|
-
|
|
1194
|
-
|
|
1200
|
+
const wagerApe = calculateWager(availableApe, strategyConfig);
|
|
1201
|
+
if (wagerApe < strategyConfig.minBetApe) {
|
|
1202
|
+
saveState(state);
|
|
1203
|
+
const response = {
|
|
1204
|
+
...baseResponse,
|
|
1205
|
+
status: 'skipped',
|
|
1206
|
+
reason: 'wager_below_minimum',
|
|
1207
|
+
wager_ape: formatApeAmount(wagerApe),
|
|
1208
|
+
};
|
|
1209
|
+
if (opts.json) console.log(JSON.stringify(response));
|
|
1210
|
+
else console.log(JSON.stringify(response, null, 2));
|
|
1211
|
+
return { shouldStop: true, waitMs: 0 };
|
|
1212
|
+
}
|
|
1195
1213
|
|
|
1196
|
-
|
|
1197
|
-
const
|
|
1198
|
-
|
|
1199
|
-
|
|
1200
|
-
|
|
1201
|
-
|
|
1202
|
-
|
|
1203
|
-
|
|
1204
|
-
|
|
1214
|
+
const selection = selectGameAndConfig(strategyConfig);
|
|
1215
|
+
const wagerApeString = formatApeAmount(wagerApe);
|
|
1216
|
+
|
|
1217
|
+
try {
|
|
1218
|
+
const playResponse = await playGame({
|
|
1219
|
+
account,
|
|
1220
|
+
game: selection.game,
|
|
1221
|
+
amountApe: wagerApeString,
|
|
1222
|
+
mode: selection.mode,
|
|
1223
|
+
balls: selection.balls,
|
|
1224
|
+
spins: selection.spins,
|
|
1225
|
+
timeoutMs,
|
|
1226
|
+
});
|
|
1227
|
+
|
|
1228
|
+
state.lastPlay = Date.now();
|
|
1229
|
+
if (playResponse?.result) {
|
|
1230
|
+
const pnlWei = (BigInt(playResponse.result.payout_wei) -
|
|
1231
|
+
BigInt(playResponse.result.buy_in_wei)).toString();
|
|
1232
|
+
state.totalPnLWei = addBigIntStrings(state.totalPnLWei, pnlWei);
|
|
1233
|
+
if (BigInt(pnlWei) >= 0n) {
|
|
1234
|
+
state.sessionWins += 1;
|
|
1235
|
+
state.consecutiveWins += 1;
|
|
1236
|
+
state.consecutiveLosses = 0;
|
|
1237
|
+
} else {
|
|
1238
|
+
state.sessionLosses += 1;
|
|
1239
|
+
state.consecutiveLosses += 1;
|
|
1240
|
+
state.consecutiveWins = 0;
|
|
1241
|
+
}
|
|
1242
|
+
}
|
|
1243
|
+
|
|
1244
|
+
saveState(state);
|
|
1245
|
+
|
|
1246
|
+
// Recalculate cooldown after state update (may change due to win/loss streaks)
|
|
1247
|
+
const newCooldownMs = requestedCooldown > 0
|
|
1248
|
+
? requestedCooldown
|
|
1249
|
+
: computeCooldownMs(strategyConfig, state);
|
|
1250
|
+
|
|
1251
|
+
const response = {
|
|
1252
|
+
...baseResponse,
|
|
1253
|
+
cooldown_ms: newCooldownMs,
|
|
1254
|
+
consecutive_wins: state.consecutiveWins,
|
|
1255
|
+
consecutive_losses: state.consecutiveLosses,
|
|
1256
|
+
status: playResponse.status,
|
|
1257
|
+
wager_ape: wagerApeString,
|
|
1258
|
+
game: playResponse.game,
|
|
1259
|
+
config: playResponse.config,
|
|
1260
|
+
tx: playResponse.tx,
|
|
1261
|
+
gameId: playResponse.gameId,
|
|
1262
|
+
game_url: playResponse.game_url,
|
|
1263
|
+
result: playResponse.result,
|
|
1264
|
+
};
|
|
1265
|
+
|
|
1266
|
+
if (opts.json) console.log(JSON.stringify(response));
|
|
1267
|
+
else console.log(JSON.stringify(response, null, 2));
|
|
1268
|
+
|
|
1269
|
+
return { shouldStop: false, waitMs: newCooldownMs };
|
|
1270
|
+
} catch (error) {
|
|
1271
|
+
saveState(state);
|
|
1272
|
+
console.error(JSON.stringify({ error: error.message }));
|
|
1273
|
+
return { shouldStop: true, waitMs: 0 };
|
|
1274
|
+
}
|
|
1275
|
+
}
|
|
1276
|
+
|
|
1277
|
+
// Run once or loop
|
|
1278
|
+
if (!loopMode) {
|
|
1279
|
+
const result = await runHeartbeat();
|
|
1280
|
+
if (result.shouldStop && result.waitMs === 0) {
|
|
1281
|
+
// Error or fatal skip - exit with appropriate code
|
|
1282
|
+
const state = loadState();
|
|
1283
|
+
const profile = loadProfile();
|
|
1284
|
+
if (profile.paused) process.exit(0);
|
|
1285
|
+
}
|
|
1286
|
+
} else {
|
|
1287
|
+
// Loop mode
|
|
1288
|
+
let running = true;
|
|
1289
|
+
process.on('SIGINT', () => {
|
|
1290
|
+
if (!opts.json) console.log('\nš Stopping continuous play...');
|
|
1291
|
+
running = false;
|
|
1205
1292
|
});
|
|
1293
|
+
process.on('SIGTERM', () => {
|
|
1294
|
+
running = false;
|
|
1295
|
+
});
|
|
1296
|
+
|
|
1297
|
+
while (running) {
|
|
1298
|
+
const result = await runHeartbeat();
|
|
1299
|
+
|
|
1300
|
+
if (!running) break;
|
|
1301
|
+
|
|
1302
|
+
if (result.shouldStop) {
|
|
1303
|
+
if (!opts.json) console.log('\nā¹ļø Stopped: cannot continue playing.');
|
|
1304
|
+
break;
|
|
1305
|
+
}
|
|
1206
1306
|
|
|
1207
|
-
|
|
1208
|
-
|
|
1209
|
-
|
|
1210
|
-
|
|
1211
|
-
|
|
1212
|
-
|
|
1213
|
-
|
|
1214
|
-
|
|
1215
|
-
|
|
1216
|
-
|
|
1217
|
-
|
|
1218
|
-
|
|
1219
|
-
|
|
1307
|
+
if (result.waitMs > 0) {
|
|
1308
|
+
if (!opts.json) {
|
|
1309
|
+
console.log(`\nā³ Waiting ${(result.waitMs / 1000).toFixed(0)}s until next bet...\n`);
|
|
1310
|
+
}
|
|
1311
|
+
await new Promise((resolve) => {
|
|
1312
|
+
const timeout = setTimeout(resolve, result.waitMs);
|
|
1313
|
+
const checkStop = setInterval(() => {
|
|
1314
|
+
if (!running) {
|
|
1315
|
+
clearTimeout(timeout);
|
|
1316
|
+
clearInterval(checkStop);
|
|
1317
|
+
resolve();
|
|
1318
|
+
}
|
|
1319
|
+
}, 500);
|
|
1320
|
+
});
|
|
1220
1321
|
}
|
|
1221
1322
|
}
|
|
1323
|
+
}
|
|
1324
|
+
});
|
|
1222
1325
|
|
|
1223
|
-
|
|
1224
|
-
|
|
1225
|
-
|
|
1226
|
-
|
|
1227
|
-
|
|
1228
|
-
|
|
1229
|
-
|
|
1230
|
-
|
|
1231
|
-
|
|
1232
|
-
|
|
1233
|
-
|
|
1326
|
+
// --- COMMAND: GAMES (Show available games and parameters) ---
|
|
1327
|
+
program
|
|
1328
|
+
.command('games')
|
|
1329
|
+
.description('List all available games and their parameters')
|
|
1330
|
+
.option('--json', 'Output JSON only')
|
|
1331
|
+
.action((opts) => {
|
|
1332
|
+
const games = GAME_REGISTRY.map((game) => {
|
|
1333
|
+
const params = [];
|
|
1334
|
+
if (game.type === 'plinko') {
|
|
1335
|
+
params.push({
|
|
1336
|
+
name: 'mode',
|
|
1337
|
+
type: 'integer',
|
|
1338
|
+
min: game.config.mode.min,
|
|
1339
|
+
max: game.config.mode.max,
|
|
1340
|
+
default: game.config.mode.default,
|
|
1341
|
+
description: 'Risk level (higher = riskier, bigger payouts)',
|
|
1342
|
+
});
|
|
1343
|
+
params.push({
|
|
1344
|
+
name: 'balls',
|
|
1345
|
+
type: 'integer',
|
|
1346
|
+
min: game.config.balls.min,
|
|
1347
|
+
max: game.config.balls.max,
|
|
1348
|
+
default: game.config.balls.default,
|
|
1349
|
+
description: 'Number of balls to drop',
|
|
1350
|
+
});
|
|
1351
|
+
} else if (game.type === 'slots') {
|
|
1352
|
+
params.push({
|
|
1353
|
+
name: 'spins',
|
|
1354
|
+
type: 'integer',
|
|
1355
|
+
min: game.config.spins.min,
|
|
1356
|
+
max: game.config.spins.max,
|
|
1357
|
+
default: game.config.spins.default,
|
|
1358
|
+
description: 'Number of spins per bet',
|
|
1359
|
+
});
|
|
1360
|
+
}
|
|
1361
|
+
return {
|
|
1362
|
+
key: game.key,
|
|
1363
|
+
name: game.name,
|
|
1364
|
+
type: game.type,
|
|
1365
|
+
aliases: game.aliases || [],
|
|
1366
|
+
contract: game.contract,
|
|
1367
|
+
parameters: params,
|
|
1234
1368
|
};
|
|
1369
|
+
});
|
|
1235
1370
|
|
|
1236
|
-
|
|
1237
|
-
|
|
1238
|
-
}
|
|
1239
|
-
|
|
1240
|
-
|
|
1241
|
-
|
|
1371
|
+
if (opts.json) {
|
|
1372
|
+
console.log(JSON.stringify({ games }, null, 2));
|
|
1373
|
+
} else {
|
|
1374
|
+
console.log('\nš° AVAILABLE GAMES\n');
|
|
1375
|
+
for (const game of games) {
|
|
1376
|
+
console.log(`${game.name} (${game.key})`);
|
|
1377
|
+
console.log(` Type: ${game.type}`);
|
|
1378
|
+
console.log(` Aliases: ${game.aliases.join(', ') || 'none'}`);
|
|
1379
|
+
console.log(' Parameters:');
|
|
1380
|
+
for (const param of game.parameters) {
|
|
1381
|
+
console.log(` --${param.name} <${param.min}-${param.max}> ${param.description} (default: ${param.default})`);
|
|
1382
|
+
}
|
|
1383
|
+
console.log('');
|
|
1384
|
+
}
|
|
1385
|
+
console.log('EXAMPLE BETS:');
|
|
1386
|
+
console.log(' apechurch bet --game jungle-plinko --amount 5 --mode 2 --balls 50');
|
|
1387
|
+
console.log(' apechurch bet --game dino-dough --amount 10 --spins 8');
|
|
1388
|
+
console.log(' apechurch bet --game bubblegum-heist --amount 5 --spins 12');
|
|
1389
|
+
console.log('');
|
|
1242
1390
|
}
|
|
1243
1391
|
});
|
|
1244
1392
|
|
|
1393
|
+
// --- COMMAND: COMMANDS (Show all commands overview) ---
|
|
1394
|
+
program
|
|
1395
|
+
.command('commands')
|
|
1396
|
+
.description('Show all available commands with examples')
|
|
1397
|
+
.action(() => {
|
|
1398
|
+
console.log(`
|
|
1399
|
+
š° APE CHURCH CLI - COMMAND REFERENCE
|
|
1400
|
+
|
|
1401
|
+
SETUP
|
|
1402
|
+
apechurch install [--username NAME] [--persona TYPE]
|
|
1403
|
+
Set up your agent wallet and register.
|
|
1404
|
+
Personas: conservative, balanced, aggressive, degen
|
|
1405
|
+
|
|
1406
|
+
apechurch register --username <NAME>
|
|
1407
|
+
Change your username.
|
|
1408
|
+
|
|
1409
|
+
STATUS
|
|
1410
|
+
apechurch status [--json]
|
|
1411
|
+
Check your wallet balance and agent status.
|
|
1412
|
+
|
|
1413
|
+
apechurch games [--json]
|
|
1414
|
+
List all available games and their parameters.
|
|
1415
|
+
|
|
1416
|
+
PLAYING
|
|
1417
|
+
apechurch heartbeat [--strategy TYPE] [--loop] [--json]
|
|
1418
|
+
Place a bet using your strategy. Use --loop to play continuously.
|
|
1419
|
+
Strategies: conservative (60s), balanced (30s), aggressive (15s), degen (10s)
|
|
1420
|
+
|
|
1421
|
+
apechurch bet --game <NAME> --amount <APE> [--mode 0-4] [--balls 1-100] [--spins 1-15]
|
|
1422
|
+
Place a manual bet on a specific game.
|
|
1423
|
+
Games: jungle-plinko, dino-dough, bubblegum-heist
|
|
1424
|
+
|
|
1425
|
+
CONTROL
|
|
1426
|
+
apechurch pause
|
|
1427
|
+
Pause autonomous play.
|
|
1428
|
+
|
|
1429
|
+
apechurch resume
|
|
1430
|
+
Resume autonomous play.
|
|
1431
|
+
|
|
1432
|
+
PROFILE
|
|
1433
|
+
apechurch profile show [--json]
|
|
1434
|
+
View your current profile settings.
|
|
1435
|
+
|
|
1436
|
+
apechurch profile set [--persona TYPE] [--username NAME]
|
|
1437
|
+
Update your profile.
|
|
1438
|
+
|
|
1439
|
+
EXAMPLES
|
|
1440
|
+
apechurch install --username CoolBot --persona balanced
|
|
1441
|
+
apechurch heartbeat --strategy aggressive --loop
|
|
1442
|
+
apechurch bet --game jungle-plinko --amount 10 --mode 3 --balls 25
|
|
1443
|
+
apechurch bet --game dino-dough --amount 5 --spins 10
|
|
1444
|
+
`);
|
|
1445
|
+
});
|
|
1446
|
+
|
|
1245
1447
|
program.parse(process.argv);
|