Skip to content

Commit 0889909

Browse files
committed
final fixes
1 parent 7b9a6f4 commit 0889909

File tree

9 files changed

+481
-544
lines changed

9 files changed

+481
-544
lines changed

ideas/newproject.txt

Lines changed: 43 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -81,4 +81,46 @@ Way to urls to open on user end somehow
8181

8282
make it so that it reacts to certain emojis/reactions
8383

84-
I mean maybe like an image can be shown or smth
84+
I mean maybe like an image can be shown or smth
85+
86+
Phase 0 — Foundations & Guardrails
87+
Audited file-store, ET timezone baseline, logging/metrics, idempotency & simple locks, least-privilege, feature flags. Accept: ET jobs trigger; every balance change logged.
88+
89+
Phase 1 — Opt-In / Opt-Out (PLAY & SEE)
90+
:coin: reaction → PLAY; /see on|off; /stopgambling fully opts out. Accept: reversible, rate-limited.
91+
92+
Phase 2 — Coins & Economy
93+
Daily +100 at 00:00 ET; /coin shows balance/streak; full ledger (grant/bet/win/loss/purchase/refund/admin). Accept: grant idempotent; balances consistent.
94+
95+
Phase 3 — Reactive Emoji & Keywords
96+
Reactions for coin/gamble/win/lose with per-user/channel cooldown; optional hype text. Accept: never reacts to opted-out users.
97+
98+
Phase 4 — Challenge Framework (PvP & Dealer)
99+
One flow: /challenge → accept/decline; auto-cancel on timeout; stake lock at accept; thread updates; optional double-or-nothing. Accept: PvP & dealer end-to-end with refunds on cancel.
100+
101+
Phase 5 — Game 1: Coin Flip
102+
Call heads/tails, flip, resolve 1:1; dealer or PvP; clean ledger & locks. Accept: correct payout, no orphans.
103+
104+
Phase 6 — Leaderboard & Announcements
105+
/leaderboard, daily top-10 announcement, weekly winners + reset (respect Sigma). Accept: posts render; weekly reset writes txs once.
106+
107+
Phase 7 — Streak Engine
108+
Qualifying action per ET day; update current/longest; /streak DM. Accept: correct across DST/boundary tests.
109+
110+
Phase 8 — Shop & Power-Ups
111+
Inventory + items: Streak Saver, Game Breaker, Sigma, Reactor. Accept: purchases debit, effects apply at right moments.
112+
113+
Phase 9 — AI Debate (Manual Payout)
114+
User starts debate; private review queue; Approve/Reject/Adjust; tx on approval. Accept: no payout without approval.
115+
116+
Phase 10 — Game 2: Typing Battle
117+
Same prompt, validate accuracy/time; dealer target time. Accept: deterministic winner; correct ledger.
118+
119+
Phase 11 — Game 3: Old Maid
120+
2–4 players, Joker loses; DMs for hands; thread updates. Accept: deterministic state machine; fair resolution.
121+
122+
Phase 12 — Game 4: Poker (Heads-Up)
123+
Hole cards via DM, actions via buttons, pot/blinds, evaluator. Accept: correct pot & hand resolution.
124+
125+
Phase 13 — Secret Coins (3 total)
126+
1-in-1,000,000 roll on qualifying actions; max 3 globally; owning all 3 → announce + 1,000,000 coins once. Accept: never >3; ownership persists; grand award triggers once.

ideas/problems+todo.txt

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -23,13 +23,17 @@ I mean maybe like an image can be shown or smth
2323

2424
URGENT:
2525

26+
PHASE 5/13
27+
2628
Lower cooldown from 60 sec so it can be good
2729
won - get more emojis
2830
lost - get more emojis
2931
gamble - maybe make it comment or actually say something?
3032

33+
make dealer work
34+
add more reactions?
35+
3136
dont let outsiders influence accept/reject
3237
OR do a only-visible message
3338

3439
fix /see on and off
35-
fix pinging in terminal

index.html

Lines changed: 102 additions & 213 deletions
Large diffs are not rendered by default.

script.js

Lines changed: 1 addition & 71 deletions
Original file line numberDiff line numberDiff line change
@@ -1,71 +1 @@
1-
const welcome = document.querySelector('.welcome');
2-
const layout = document.querySelector('.layout');
3-
const enterHint = document.querySelector('.enter-hint');
4-
5-
let canEnter = false;
6-
7-
setTimeout(() => {
8-
if (enterHint) {
9-
enterHint.hidden = false;
10-
requestAnimationFrame(() => enterHint.classList.add('show'));
11-
}
12-
canEnter = true;
13-
}, 3000);
14-
15-
window.addEventListener('keydown', (e) => {
16-
if (!welcome || welcome.classList.contains('hidden')) return;
17-
if (e.key === 'Enter' && canEnter) {
18-
19-
welcome.classList.add('hidden');
20-
welcome.setAttribute('aria-hidden', 'true');
21-
if (layout) layout.setAttribute('aria-hidden', 'false');
22-
23-
const firstLink = document.querySelector('#toc a');
24-
firstLink?.focus();
25-
}
26-
});
27-
28-
const toc = document.getElementById('toc');
29-
const links = Array.from(toc.querySelectorAll('a'));
30-
31-
links.forEach(a => {
32-
a.addEventListener('click', e => {
33-
e.preventDefault();
34-
const id = a.getAttribute('href').slice(1);
35-
const el = document.getElementById(id);
36-
if (el) el.scrollIntoView({ behavior: 'smooth', block: 'start' });
37-
history.replaceState(null, '', `#${id}`);
38-
});
39-
});
40-
41-
const observer = new IntersectionObserver(
42-
entries => {
43-
entries.forEach(entry => {
44-
const id = entry.target.id;
45-
const link = links.find(l => l.getAttribute('href') === `#${id}`);
46-
if (!link) return;
47-
if (entry.isIntersecting) {
48-
links.forEach(l => l.classList.remove('active'));
49-
link.classList.add('active');
50-
}
51-
});
52-
}, { rootMargin: '-40% 0px -55% 0px', threshold: 0.01 }
53-
);
54-
55-
document.querySelectorAll('main section[id]').forEach(sec => observer.observe(sec));
56-
57-
document.querySelectorAll('.copy').forEach(btn => {
58-
btn.addEventListener('click', async () => {
59-
const target = document.querySelector(btn.dataset.copy);
60-
const text = target?.innerText || '';
61-
try {
62-
await navigator.clipboard.writeText(text);
63-
const original = btn.textContent;
64-
btn.textContent = 'Copied!';
65-
setTimeout(() => (btn.textContent = original), 1200);
66-
} catch {
67-
btn.textContent = 'Copy failed';
68-
setTimeout(() => (btn.textContent = 'Copy'), 1200);
69-
}
70-
});
71-
});
1+
//nothing needed :D

slack-bot/data/state.json

Lines changed: 31 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -44,6 +44,17 @@
4444
"currentStreak": 0,
4545
"longestStreak": 0
4646
}
47+
},
48+
"U090B1V22BD": {
49+
"id": "U090B1V22BD",
50+
"play": true,
51+
"see": false,
52+
"createdAt": "2025-10-07T03:43:17.846Z",
53+
"updatedAt": "2025-10-07T03:45:17.573Z",
54+
"stats": {
55+
"currentStreak": 0,
56+
"longestStreak": 0
57+
}
4758
}
4859
},
4960
"balances": {
@@ -66,6 +77,11 @@
6677
"userId": "U0947SL6AKB",
6778
"amount": 90,
6879
"updatedAt": "2025-10-06T04:35:11.093Z"
80+
},
81+
"U090B1V22BD": {
82+
"userId": "U090B1V22BD",
83+
"amount": 100,
84+
"updatedAt": "2025-10-07T03:45:18.363Z"
6985
}
7086
},
7187
"inventory": {},
@@ -169,6 +185,16 @@
169185
"refId": "challenge:e4e5eee9-abbf-46ed-a25e-fcd57ef8883f",
170186
"idemKey": "challenge:e4e5eee9-abbf-46ed-a25e-fcd57ef8883f:stake:U0828FYS2UC",
171187
"createdAt": "2025-10-06T04:35:11.096Z"
188+
},
189+
{
190+
"txId": "d7f0c999-4a97-4e8b-94f2-3ab2841a5212",
191+
"userId": "U090B1V22BD",
192+
"type": "grant",
193+
"amount": 100,
194+
"balanceAfter": 100,
195+
"refId": "daily_grant",
196+
"idemKey": "daily:null",
197+
"createdAt": "2025-10-07T03:45:18.363Z"
172198
}
173199
],
174200
"games": {
@@ -328,6 +354,10 @@
328354
"tx:U0828FYS2UC:challenge:e4e5eee9-abbf-46ed-a25e-fcd57ef8883f:stake:U0828FYS2UC": {
329355
"key": "tx:U0828FYS2UC:challenge:e4e5eee9-abbf-46ed-a25e-fcd57ef8883f:stake:U0828FYS2UC",
330356
"createdAt": "2025-10-06T04:35:11.095Z"
357+
},
358+
"tx:U090B1V22BD:daily:null": {
359+
"key": "tx:U090B1V22BD:daily:null",
360+
"createdAt": "2025-10-07T03:45:18.359Z"
331361
}
332362
},
333363
"featureFlags": {
@@ -341,5 +371,5 @@
341371
"aiDebate": true
342372
},
343373
"createdAt": "2025-10-05T18:28:11.113Z",
344-
"updatedAt": "2025-10-06T04:35:11.097Z"
374+
"updatedAt": "2025-10-07T03:45:18.363Z"
345375
}

slack-bot/src/app.ts

Lines changed: 36 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -26,15 +26,51 @@ async function init() {
2626
const dateEt = DateTime.now().setZone(CONFIG.etTz).toISODate()!;
2727
await runDailyGrantForAll(dateEt);
2828
logger.info("Daily tick (ET) complete", { dateEt });
29+
30+
if (CONFIG.leaderboardChannelId) {
31+
try {
32+
await app.client.chat.postMessage({
33+
channel: CONFIG.leaderboardChannelId,
34+
text: buildTop10Text(),
35+
});
36+
logger.info("Posted daily Top 10", { channel: CONFIG.leaderboardChannelId });
37+
} catch (e: any) {
38+
logger.warn("Failed to post daily Top 10", { error: e?.message });
39+
}
40+
}
2941
});
3042

3143
// add weekly reset, leaderboard
3244
scheduleWeeklyMondayEt("weekly-monday-et", async () => {
3345
const weekOf = DateTime.now().setZone(CONFIG.etTz).toISODate()!;
3446
logger.info("Weekly tick (ET)", { weekOf });
47+
48+
if (CONFIG.leaderboardChannelId) {
49+
try {
50+
await app.client.chat.postMessage({
51+
channel: CONFIG.leaderboardChannelId,
52+
text: buildTop10Text(),
53+
});
54+
logger.info("Posted weekly Top 10", { channel: CONFIG.leaderboardChannelId });
55+
} catch (e: any) {
56+
logger.warn("Failed to post weekly Top 10", { error: e?.message });
57+
}
58+
}
3559
});
3660
}
3761

62+
function buildTop10Text(): string {
63+
const s = store.get();
64+
const balances = Object.values(s.balances || {}); // { userId, amount }
65+
const top = balances
66+
.sort((a: any, b: any) => (b.amount ?? 0) - (a.amount ?? 0))
67+
.slice(0, 10);
68+
69+
const lines = top.map((b: any, i: number) => `${i + 1}. <@${b.userId}> — ${b.amount} coins`);
70+
return `🏆 *Top 10 Coin Holders*\n\n${lines.join("\n")}${top.length === 0 ? "_No players yet._" : ""}`;
71+
}
72+
73+
3874
init().catch((e) => {
3975
logger.error("Fatal init error idiot", { error: e?.message || String(e)});
4076
process.exit(1);

slack-bot/src/config.ts

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -25,4 +25,6 @@ export const CONFIG = {
2525
stateFile: STATE_FILE,
2626
logLevel: LOG_LEVEL,
2727
defaultFlags: DEFAULT_FLAGS,
28+
leaderboardChannelId: process.env.SLACK_LEADERBOARD_CHANNEL_ID || "C08SKC6P85V",
29+
2830
};

0 commit comments

Comments
 (0)