@ape-church/skill 1.0.2 ā 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/SKILL.md +389 -152
- package/assets/SKILL.md +389 -152
- package/bin/cli.js +364 -150
- package/package.json +1 -1
package/bin/cli.js
CHANGED
|
@@ -7,13 +7,25 @@ import path from 'path';
|
|
|
7
7
|
import {
|
|
8
8
|
createPublicClient,
|
|
9
9
|
createWalletClient,
|
|
10
|
+
defineChain,
|
|
10
11
|
encodeAbiParameters,
|
|
11
12
|
formatEther,
|
|
12
13
|
http,
|
|
13
14
|
parseEther,
|
|
14
15
|
} from 'viem';
|
|
15
16
|
import { privateKeyToAccount, generatePrivateKey } from 'viem/accounts';
|
|
16
|
-
|
|
17
|
+
|
|
18
|
+
const apechain = defineChain({
|
|
19
|
+
id: 33139,
|
|
20
|
+
name: 'ApeChain',
|
|
21
|
+
nativeCurrency: { name: 'ApeCoin', symbol: 'APE', decimals: 18 },
|
|
22
|
+
rpcUrls: {
|
|
23
|
+
default: { http: ['https://rpc.apechain.com/http'] },
|
|
24
|
+
},
|
|
25
|
+
blockExplorers: {
|
|
26
|
+
default: { name: 'ApeScan', url: 'https://apescan.io' },
|
|
27
|
+
},
|
|
28
|
+
});
|
|
17
29
|
import { SiweMessage } from 'siwe';
|
|
18
30
|
import { GAME_REGISTRY, listGames, resolveGame } from '../registry.js';
|
|
19
31
|
|
|
@@ -402,7 +414,7 @@ function getStrategyConfig(strategy) {
|
|
|
402
414
|
);
|
|
403
415
|
const configs = {
|
|
404
416
|
conservative: {
|
|
405
|
-
minBetApe:
|
|
417
|
+
minBetApe: 1,
|
|
406
418
|
targetBetPct: 0.05,
|
|
407
419
|
maxBetPct: 0.1,
|
|
408
420
|
baseCooldownMs: 60 * 1000, // 60 seconds
|
|
@@ -411,7 +423,7 @@ function getStrategyConfig(strategy) {
|
|
|
411
423
|
gameWeights: defaultWeights,
|
|
412
424
|
},
|
|
413
425
|
balanced: {
|
|
414
|
-
minBetApe:
|
|
426
|
+
minBetApe: 1,
|
|
415
427
|
targetBetPct: 0.08,
|
|
416
428
|
maxBetPct: 0.15,
|
|
417
429
|
baseCooldownMs: 30 * 1000, // 30 seconds
|
|
@@ -420,7 +432,7 @@ function getStrategyConfig(strategy) {
|
|
|
420
432
|
gameWeights: defaultWeights,
|
|
421
433
|
},
|
|
422
434
|
aggressive: {
|
|
423
|
-
minBetApe:
|
|
435
|
+
minBetApe: 1,
|
|
424
436
|
targetBetPct: 0.12,
|
|
425
437
|
maxBetPct: 0.25,
|
|
426
438
|
baseCooldownMs: 15 * 1000, // 15 seconds
|
|
@@ -429,7 +441,7 @@ function getStrategyConfig(strategy) {
|
|
|
429
441
|
gameWeights: defaultWeights,
|
|
430
442
|
},
|
|
431
443
|
degen: {
|
|
432
|
-
minBetApe:
|
|
444
|
+
minBetApe: 1,
|
|
433
445
|
targetBetPct: 0.2,
|
|
434
446
|
maxBetPct: 0.35,
|
|
435
447
|
baseCooldownMs: 10 * 1000, // 10 seconds
|
|
@@ -844,25 +856,37 @@ program
|
|
|
844
856
|
console.log('You can retry later with: apechurch register --username <NAME>');
|
|
845
857
|
}
|
|
846
858
|
|
|
847
|
-
// 4. The Handshake
|
|
859
|
+
// 4. The Handshake
|
|
848
860
|
console.log('\nSETUP COMPLETE');
|
|
849
861
|
console.log('---------------------------------------');
|
|
850
862
|
console.log(`AGENT ADDRESS: ${address}`);
|
|
851
863
|
console.log(`USERNAME: ${username}`);
|
|
852
|
-
if (!usernameWasProvided) {
|
|
853
|
-
console.log(' (Change anytime: apechurch register --username <YOUR_NAME>)');
|
|
854
|
-
}
|
|
855
864
|
console.log(`PERSONA: ${persona}`);
|
|
856
865
|
console.log('');
|
|
857
|
-
console.log('
|
|
858
|
-
console.log('
|
|
859
|
-
console.log(
|
|
860
|
-
|
|
861
|
-
);
|
|
862
|
-
console.log('
|
|
863
|
-
console.log('
|
|
864
|
-
console.log('
|
|
865
|
-
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');
|
|
866
890
|
console.log('---------------------------------------');
|
|
867
891
|
});
|
|
868
892
|
|
|
@@ -1071,163 +1095,353 @@ program
|
|
|
1071
1095
|
// --- COMMAND: HEARTBEAT (Autonomous Loop) ---
|
|
1072
1096
|
program
|
|
1073
1097
|
.command('heartbeat')
|
|
1074
|
-
.option('--strategy <name>', 'conservative | balanced | aggressive')
|
|
1098
|
+
.option('--strategy <name>', 'conservative | balanced | aggressive | degen')
|
|
1075
1099
|
.option('--cooldown <ms>', 'Minimum ms between plays (0 = use strategy cooldown)', '0')
|
|
1076
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)')
|
|
1077
1102
|
.option('--json', 'Output JSON only')
|
|
1078
1103
|
.action(async (opts) => {
|
|
1079
1104
|
const account = getWallet();
|
|
1080
|
-
const state = loadState();
|
|
1081
|
-
const profile = loadProfile();
|
|
1082
|
-
const now = Date.now();
|
|
1083
|
-
|
|
1084
|
-
// Check if paused - skip gracefully without fetching balance
|
|
1085
|
-
if (profile.paused) {
|
|
1086
|
-
state.lastHeartbeat = now;
|
|
1087
|
-
saveState(state);
|
|
1088
|
-
const response = {
|
|
1089
|
-
action: 'heartbeat',
|
|
1090
|
-
status: 'skipped',
|
|
1091
|
-
reason: 'paused',
|
|
1092
|
-
message: 'Autonomous play is paused. Run `apechurch resume` to continue.',
|
|
1093
|
-
address: account.address,
|
|
1094
|
-
paused: true,
|
|
1095
|
-
};
|
|
1096
|
-
if (opts.json) console.log(JSON.stringify(response));
|
|
1097
|
-
else console.log(JSON.stringify(response, null, 2));
|
|
1098
|
-
return;
|
|
1099
|
-
}
|
|
1100
|
-
|
|
1101
|
-
state.lastHeartbeat = now;
|
|
1102
|
-
if (opts.strategy) state.strategy = normalizeStrategy(opts.strategy);
|
|
1103
|
-
else if (profile.persona) state.strategy = normalizeStrategy(profile.persona);
|
|
1104
1105
|
const requestedCooldown = parseNonNegativeInt(opts.cooldown, 'cooldown');
|
|
1105
|
-
if (requestedCooldown > 0) state.cooldownMs = requestedCooldown;
|
|
1106
1106
|
const timeoutMs = parseNonNegativeInt(opts.timeout, 'timeout');
|
|
1107
|
+
const loopMode = Boolean(opts.loop);
|
|
1107
1108
|
|
|
1108
|
-
|
|
1109
|
-
|
|
1110
|
-
try {
|
|
1111
|
-
balance = await publicClient.getBalance({ address: account.address });
|
|
1112
|
-
} catch (error) {
|
|
1113
|
-
console.error(JSON.stringify({ error: `Failed to fetch balance: ${sanitizeError(error)}` }));
|
|
1114
|
-
process.exit(1);
|
|
1109
|
+
if (loopMode && !opts.json) {
|
|
1110
|
+
console.log('š° Starting continuous play mode (Ctrl+C to stop)...\n');
|
|
1115
1111
|
}
|
|
1116
1112
|
|
|
1117
|
-
|
|
1118
|
-
|
|
1119
|
-
|
|
1120
|
-
|
|
1121
|
-
|
|
1122
|
-
|
|
1123
|
-
|
|
1124
|
-
|
|
1125
|
-
|
|
1126
|
-
|
|
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
|
+
}
|
|
1127
1135
|
|
|
1128
|
-
|
|
1129
|
-
|
|
1130
|
-
strategy
|
|
1131
|
-
|
|
1132
|
-
|
|
1133
|
-
|
|
1134
|
-
|
|
1135
|
-
|
|
1136
|
-
|
|
1137
|
-
|
|
1138
|
-
|
|
1139
|
-
|
|
1140
|
-
|
|
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
|
+
}
|
|
1141
1149
|
|
|
1142
|
-
|
|
1143
|
-
|
|
1144
|
-
const
|
|
1145
|
-
|
|
1146
|
-
|
|
1147
|
-
|
|
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,
|
|
1148
1172
|
};
|
|
1149
|
-
if (opts.json) console.log(JSON.stringify(response));
|
|
1150
|
-
else console.log(JSON.stringify(response, null, 2));
|
|
1151
|
-
return;
|
|
1152
|
-
}
|
|
1153
1173
|
|
|
1154
|
-
|
|
1155
|
-
|
|
1156
|
-
|
|
1157
|
-
|
|
1158
|
-
|
|
1159
|
-
|
|
1160
|
-
|
|
1161
|
-
|
|
1162
|
-
|
|
1163
|
-
|
|
1164
|
-
|
|
1165
|
-
}
|
|
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
|
+
}
|
|
1166
1185
|
|
|
1167
|
-
|
|
1168
|
-
|
|
1169
|
-
|
|
1170
|
-
|
|
1171
|
-
|
|
1172
|
-
|
|
1173
|
-
|
|
1174
|
-
|
|
1175
|
-
|
|
1176
|
-
|
|
1177
|
-
|
|
1178
|
-
|
|
1179
|
-
|
|
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
|
+
}
|
|
1180
1199
|
|
|
1181
|
-
|
|
1182
|
-
|
|
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
|
+
}
|
|
1183
1213
|
|
|
1184
|
-
|
|
1185
|
-
const
|
|
1186
|
-
|
|
1187
|
-
|
|
1188
|
-
|
|
1189
|
-
|
|
1190
|
-
|
|
1191
|
-
|
|
1192
|
-
|
|
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;
|
|
1292
|
+
});
|
|
1293
|
+
process.on('SIGTERM', () => {
|
|
1294
|
+
running = false;
|
|
1193
1295
|
});
|
|
1194
1296
|
|
|
1195
|
-
|
|
1196
|
-
|
|
1197
|
-
|
|
1198
|
-
|
|
1199
|
-
|
|
1200
|
-
if (
|
|
1201
|
-
|
|
1202
|
-
|
|
1203
|
-
|
|
1204
|
-
|
|
1205
|
-
|
|
1206
|
-
|
|
1207
|
-
|
|
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
|
+
}
|
|
1306
|
+
|
|
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
|
+
});
|
|
1208
1321
|
}
|
|
1209
1322
|
}
|
|
1323
|
+
}
|
|
1324
|
+
});
|
|
1210
1325
|
|
|
1211
|
-
|
|
1212
|
-
|
|
1213
|
-
|
|
1214
|
-
|
|
1215
|
-
|
|
1216
|
-
|
|
1217
|
-
|
|
1218
|
-
|
|
1219
|
-
|
|
1220
|
-
|
|
1221
|
-
|
|
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,
|
|
1222
1368
|
};
|
|
1369
|
+
});
|
|
1223
1370
|
|
|
1224
|
-
|
|
1225
|
-
|
|
1226
|
-
}
|
|
1227
|
-
|
|
1228
|
-
|
|
1229
|
-
|
|
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('');
|
|
1230
1390
|
}
|
|
1231
1391
|
});
|
|
1232
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
|
+
|
|
1233
1447
|
program.parse(process.argv);
|