ai-cto 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/docs/STACK.md ADDED
@@ -0,0 +1,204 @@
1
+ # โšก AI CTO โ€” Technical Architecture & Stack Document
2
+
3
+ > **Goal:** Validate if choosing AI models is fun. Optimized for shipping in a single weekend with zero backend, pure deterministic logic, and rapid iteration via JSON configuration.
4
+
5
+ ---
6
+
7
+ ## ๐ŸŽฏ Guiding Principles
8
+
9
+ - ๐ŸŽฒ **100% Deterministic:** Seeded RNG ensures every player faces identical daily challenges.
10
+ - ๐Ÿ“Š **Data-Driven Design:** Game rules, models, and requests are fully configurable via JSON schemas.
11
+ - โšก **Zero Backend Architecture:** No authentication, no databases, no APIs, no network dependency.
12
+ - ๐Ÿงช **Test-Driven Engine:** Pure TypeScript core logic decoupled completely from the UI layer.
13
+
14
+ ---
15
+
16
+ ## ๐Ÿ› ๏ธ Technology Stack Overview
17
+
18
+ | Domain | Technology | Rationale |
19
+ | :--- | :--- | :--- |
20
+ | **Framework** | React 19 + Vite + TypeScript | Blazing fast dev loop, minimal bundle size, ideal for static deployment |
21
+ | **Styling** | Tailwind CSS + shadcn/ui | Accelerated component building with zero custom CSS except animations |
22
+ | **State** | Zustand | Ultra-lightweight, single centralized state store |
23
+ | **Persistence** | LocalStorage | Simple client-side persistence for game state and settings |
24
+ | **Routing** | React Router v7 | Seamless single-page navigation |
25
+ | **Animations** | Framer Motion | Fluid card transitions, score incrementing, and cash feedback |
26
+ | **Icons** | Lucide React | Clean modern SVG icons |
27
+ | **Audio** | Howler.js / HTML5 Audio | Snappy sound effects (clicks, cash register, failures) |
28
+ | **Testing** | Vitest | Fast headless CLI unit testing for engine logic |
29
+ | **Deployment** | Vercel / Cloudflare Pages | Instant static deployment with edge distribution |
30
+
31
+ ---
32
+
33
+ ## ๐Ÿ—‚๏ธ Project Directory Structure
34
+
35
+ ```
36
+ aicto/
37
+ โ”œโ”€โ”€ src/
38
+ โ”‚ โ”œโ”€โ”€ assets/ # Sound FX, custom graphics, and icons
39
+ โ”‚ โ”‚ โ”œโ”€โ”€ icons/
40
+ โ”‚ โ”‚ โ””โ”€โ”€ sounds/
41
+ โ”‚ โ”œโ”€โ”€ components/ # Reusable UI components (shadcn/ui based)
42
+ โ”‚ โ”‚ โ”œโ”€โ”€ EndScreen.tsx
43
+ โ”‚ โ”‚ โ”œโ”€โ”€ Header.tsx
44
+ โ”‚ โ”‚ โ”œโ”€โ”€ ModelCard.tsx
45
+ โ”‚ โ”‚ โ”œโ”€โ”€ RequestCard.tsx
46
+ โ”‚ โ”‚ โ””โ”€โ”€ ScoreBar.tsx
47
+ โ”‚ โ”œโ”€โ”€ data/ # Static game JSON data
48
+ โ”‚ โ”‚ โ”œโ”€โ”€ encyclopedia.json
49
+ โ”‚ โ”‚ โ”œโ”€โ”€ models.json
50
+ โ”‚ โ”‚ โ””โ”€โ”€ requests.json
51
+ โ”‚ โ”œโ”€โ”€ engine/ # Pure TypeScript game simulation engine
52
+ โ”‚ โ”‚ โ”œโ”€โ”€ economy.ts
53
+ โ”‚ โ”‚ โ”œโ”€โ”€ evaluate.ts
54
+ โ”‚ โ”‚ โ”œโ”€โ”€ rng.ts
55
+ โ”‚ โ”‚ โ”œโ”€โ”€ scoring.ts
56
+ โ”‚ โ”‚ โ””โ”€โ”€ seed.ts
57
+ โ”‚ โ”œโ”€โ”€ hooks/ # Custom React hooks
58
+ โ”‚ โ”œโ”€โ”€ pages/ # Page-level routes
59
+ โ”‚ โ”‚ โ”œโ”€โ”€ Encyclopedia.tsx
60
+ โ”‚ โ”‚ โ”œโ”€โ”€ Game.tsx
61
+ โ”‚ โ”‚ โ”œโ”€โ”€ Home.tsx
62
+ โ”‚ โ”‚ โ”œโ”€โ”€ Results.tsx
63
+ โ”‚ โ”‚ โ””โ”€โ”€ Settings.tsx
64
+ โ”‚ โ”œโ”€โ”€ store/ # State management
65
+ โ”‚ โ”‚ โ””โ”€โ”€ game.ts
66
+ โ”‚ โ”œโ”€โ”€ types/ # TypeScript interfaces & types
67
+ โ”‚ โ””โ”€โ”€ utils/ # Helper functions
68
+ โ””โ”€โ”€ tests/ # Engine unit tests (Vitest)
69
+ ```
70
+
71
+ ---
72
+
73
+ ## ๐Ÿ“ Data Contracts & JSON Schemas
74
+
75
+ ### 1. Request Schema (`requests.json`)
76
+
77
+ ```json
78
+ {
79
+ "id": 12,
80
+ "title": "Generate SQL query for analytics dashboard",
81
+ "category": "coding",
82
+ "difficulty": "medium",
83
+ "latencyRequirement": 2.0,
84
+ "qualityRequirement": 3,
85
+ "reward": 18.00,
86
+ "penalty": -30.00
87
+ }
88
+ ```
89
+
90
+ ### 2. Model Schema (`models.json`)
91
+
92
+ ```json
93
+ {
94
+ "id": "nano",
95
+ "name": "Nano",
96
+ "cost": 0.03,
97
+ "latency": 0.4,
98
+ "quality": 2,
99
+ "coding": 2,
100
+ "reasoning": 1,
101
+ "vision": 0,
102
+ "context": 1
103
+ }
104
+ ```
105
+
106
+ ---
107
+
108
+ ## ๐Ÿง  Game Engine Logic & Evaluation Pipeline
109
+
110
+ The game engine is pure TypeScript with zero React dependencies, allowing direct CLI execution and unit testing via Vitest.
111
+
112
+ ```mermaid
113
+ flowchart TD
114
+ Data[๐Ÿ“„ JSON Data] --> Engine[โšก Game Engine]
115
+ Req[๐Ÿ“ฅ Request Requirements] --> Eval[๐Ÿงช evaluate request, model ]
116
+ Mod[๐Ÿค– Model Capabilities] --> Eval
117
+ Eval --> Outcome{Success Check}
118
+ Outcome -- Success --> Profit[๐Ÿ’ฐ Calculate Profit & Bonus]
119
+ Outcome -- Failure --> Refund[๐Ÿ“‰ Deduct Penalty & Trust]
120
+ Profit --> Store[๐Ÿ“ฆ Zustand Game Store]
121
+ Refund --> Store
122
+ Store --> UI[๐Ÿ’ป React UI & LocalStorage]
123
+ ```
124
+
125
+ ### Scoring & Failure Probability Formula
126
+
127
+ Success is probabilistic when model capabilities fall below required thresholds:
128
+
129
+ | Quality Match Standard | Success Probability | Impact |
130
+ | :--- | :--- | :--- |
131
+ | **Perfect Match** (`Model >= Requirement`) | `100%` | Full Reward Granted |
132
+ | **Close Match** (`Difference = -1`) | `80%` | Minor failure risk |
133
+ | **Below Standard** (`Difference = -2`) | `35%` | High failure risk |
134
+ | **Far Below** (`Difference <= -3`) | `5%` | Almost guaranteed failure penalty |
135
+
136
+ ---
137
+
138
+ ## ๐Ÿ“ Vector-Based Capability Architecture
139
+
140
+ To support generic capability scoring without per-request hardcoding, requests and models are represented as multidimensional capability vectors:
141
+
142
+ ### Vector Definition
143
+
144
+ ```typescript
145
+ export interface CapabilityVector {
146
+ quality: number;
147
+ reasoning: number;
148
+ coding: number;
149
+ vision: number;
150
+ context: number;
151
+ latency: number;
152
+ }
153
+
154
+ export interface Model {
155
+ id: string;
156
+ cost: number;
157
+ capabilities: CapabilityVector;
158
+ }
159
+
160
+ export interface RequestRequirements {
161
+ requirements: CapabilityVector;
162
+ maxLatency: number;
163
+ reward: number;
164
+ penalty: number;
165
+ }
166
+ ```
167
+
168
+ > [!TIP]
169
+ > **Extensibility:** Using vector scoring allows introducing new capabilities (e.g. `multilingual`, `audio`, `functionCalling`) by updating vectors in `models.json` and `requests.json` without modifying core engine evaluation code.
170
+
171
+ ---
172
+
173
+ ## ๐ŸŽฒ Randomness & Seeded RNG
174
+
175
+ To enable fair daily competitive scoring without a server:
176
+ - `seedrandom` provides pseudo-random outcomes based on the current date string (e.g., `2026-08-01`).
177
+ - All players face identical request orders, failure rolls, and scoring conditions on any given day.
178
+
179
+ ---
180
+
181
+ ## ๐Ÿ“ˆ Minimal Client Analytics
182
+
183
+ Client-side event tracking captures essential gameplay metrics without requiring a custom backend:
184
+
185
+ - ๐Ÿšช **Drop-off Points:** Identify requests where players exit early.
186
+ - โš ๏ธ **Bottleneck Identification:** Track requests with highest failure rates.
187
+ - ๐Ÿ”„ **Replay Frequency:** Monitor immediate replay button clicks.
188
+ - โฑ๏ธ **Completion Time:** Average duration to complete 20 requests.
189
+ - ๐Ÿ“Š **Model Bias:** Distribution of Nano vs Mini vs Large selections.
190
+
191
+ ---
192
+
193
+ ## ๐Ÿ“ฆ Required Libraries Summary
194
+
195
+ | Category | Package | Purpose |
196
+ | :--- | :--- | :--- |
197
+ | **State** | `zustand` | Store global game state |
198
+ | **Animation** | `framer-motion` | Micro-animations and page transitions |
199
+ | **Sound** | `howler` | Fast web audio playback |
200
+ | **RNG** | `seedrandom` | Deterministic daily random seeds |
201
+ | **Class Helpers** | `clsx` + `tailwind-merge` | Conditional utility class merging |
202
+ | **Icons** | `lucide-react` | Dashboard and card icons |
203
+ | **Validation** | `zod` | JSON runtime schema validation |
204
+ | **Testing** | `vitest` | Headless unit testing for game engine |
package/package.json ADDED
@@ -0,0 +1,20 @@
1
+ {
2
+ "name": "ai-cto",
3
+ "version": "0.1.0",
4
+ "description": "Run an AI startup for 5 minutes (Terminal CLI Edition)",
5
+ "type": "module",
6
+ "bin": {
7
+ "ai-cto": "./bin/cli.js"
8
+ },
9
+ "scripts": {
10
+ "play": "node ./bin/cli.js",
11
+ "test": "node ./scripts/playtest.js"
12
+ },
13
+ "keywords": [
14
+ "cli",
15
+ "game",
16
+ "ai",
17
+ "simulation"
18
+ ],
19
+ "license": "MIT"
20
+ }
@@ -0,0 +1,147 @@
1
+ import { evaluateChoice, MODELS, REQUESTS } from '../bin/cli.js'; // or import game evaluator logic
2
+
3
+ // ---------------------------------------------------------
4
+ // Playtest Simulator Engine
5
+ // ---------------------------------------------------------
6
+
7
+ function runSimulatedGame(strategyName, strategyFn) {
8
+ let capital = 100.00;
9
+ let trust = 85;
10
+ let totalRevenue = 0;
11
+ let totalCost = 0;
12
+ let successes = 0;
13
+ let failures = 0;
14
+ const turnLogs = [];
15
+
16
+ for (let i = 0; i < REQUESTS.length; i++) {
17
+ const req = REQUESTS[i];
18
+ const selectedModel = strategyFn(req, i);
19
+
20
+ const res = evaluateChoice(selectedModel, req);
21
+ capital += res.profit;
22
+ trust = Math.min(100, Math.max(0, trust + res.trustDelta));
23
+ totalCost += selectedModel.cost;
24
+
25
+ if (res.success) {
26
+ successes++;
27
+ totalRevenue += req.reward;
28
+ } else {
29
+ failures++;
30
+ totalRevenue += req.penalty;
31
+ }
32
+
33
+ turnLogs.push({
34
+ turn: i + 1,
35
+ reqId: req.id,
36
+ title: req.title,
37
+ difficulty: req.diff,
38
+ modelChosen: selectedModel.name,
39
+ success: res.success,
40
+ profit: res.profit,
41
+ trustDelta: res.trustDelta,
42
+ headline: res.headline
43
+ });
44
+ }
45
+
46
+ let rank = 'C Tier (Break-even)';
47
+ if (capital > 250 && trust >= 90) rank = 'S Tier (Unicorn Founder)';
48
+ else if (capital > 150) rank = 'A Tier (Profitable Startup)';
49
+ else if (capital > 50) rank = 'B Tier (Sustainable Ops)';
50
+ else if (capital < 0) rank = 'Bankrupt Founder';
51
+
52
+ return {
53
+ strategyName,
54
+ capital,
55
+ trust,
56
+ totalRevenue,
57
+ totalCost,
58
+ successes,
59
+ failures,
60
+ rank,
61
+ turnLogs
62
+ };
63
+ }
64
+
65
+ // ---------------------------------------------------------
66
+ // Strategies
67
+ // ---------------------------------------------------------
68
+
69
+ // 1. Optimal Strategy (Nano for Low, Mini for Med, Large for High)
70
+ const optimalStrategy = (req) => {
71
+ if (req.diff === 'Low') return MODELS[0]; // Nano
72
+ if (req.diff === 'Medium') return MODELS[1]; // Mini
73
+ return MODELS[2]; // Large
74
+ };
75
+
76
+ // 2. Nano Spam Strategy (Nano for everything)
77
+ const nanoSpamStrategy = () => MODELS[0];
78
+
79
+ // 3. Large Safe Strategy (Large for everything)
80
+ const largeSafeStrategy = () => MODELS[2];
81
+
82
+ // 4. Random Strategy
83
+ const randomStrategy = () => MODELS[Math.floor(Math.random() * MODELS.length)];
84
+
85
+ // ---------------------------------------------------------
86
+ // Run 10 Runs per Strategy & Record Anomalies
87
+ // ---------------------------------------------------------
88
+ console.log('================================================================');
89
+ console.log('๐Ÿงช AI CTO โ€” AUTOMATED SIMULATION & ANOMALY DETECTION SUITE');
90
+ console.log('================================================================\n');
91
+
92
+ const RUNS = 10;
93
+ const strategies = [
94
+ { name: 'Optimal Strategy', fn: optimalStrategy },
95
+ { name: 'Nano Spam Strategy', fn: nanoSpamStrategy },
96
+ { name: 'Large Safe Strategy', fn: largeSafeStrategy },
97
+ { name: 'Random Choice Strategy', fn: randomStrategy }
98
+ ];
99
+
100
+ const allResults = [];
101
+ const requestFailureTracker = {};
102
+
103
+ REQUESTS.forEach(r => { requestFailureTracker[r.id] = { title: r.title, diff: r.diff, failures: 0, total: 0 }; });
104
+
105
+ strategies.forEach(strat => {
106
+ console.log(`\n--- Running 10 Playthroughs: ${strat.name} ---`);
107
+ const stratRuns = [];
108
+
109
+ for (let run = 1; run <= RUNS; run++) {
110
+ const result = runSimulatedGame(strat.name, strat.fn);
111
+ stratRuns.push(result);
112
+
113
+ result.turnLogs.forEach(log => {
114
+ requestFailureTracker[log.reqId].total++;
115
+ if (!log.success) requestFailureTracker[log.reqId].failures++;
116
+ });
117
+
118
+ console.log(` Run #${run.toString().padStart(2)}: Capital = $${result.capital.toFixed(2).padStart(7)} | Trust = ${result.trust.toString().padStart(3)}% | Score = ${result.successes}/20 Successes | Rank = ${result.rank}`);
119
+ }
120
+
121
+ const avgCapital = stratRuns.reduce((acc, r) => acc + r.capital, 0) / RUNS;
122
+ const avgTrust = stratRuns.reduce((acc, r) => acc + r.trust, 0) / RUNS;
123
+ const avgSuccess = stratRuns.reduce((acc, r) => acc + r.successes, 0) / RUNS;
124
+
125
+ console.log(` ๐Ÿ“Š SUMMARY (${strat.name}): Avg Profit = $${avgCapital.toFixed(2)} | Avg Trust = ${avgTrust.toFixed(1)}% | Avg Wins = ${avgSuccess.toFixed(1)}/20`);
126
+ allResults.push({ strat: strat.name, avgCapital, avgTrust, avgSuccess, stratRuns });
127
+ });
128
+
129
+ // ---------------------------------------------------------
130
+ // Anomaly Analysis
131
+ // ---------------------------------------------------------
132
+ console.log('\n================================================================');
133
+ console.log('๐Ÿ” ANOMALY DETECTION REPORT');
134
+ console.log('================================================================\n');
135
+
136
+ console.log('1. High Failure Rate Bottlenecks (> 50% Failure across all runs):');
137
+ Object.values(requestFailureTracker).forEach(item => {
138
+ const failRate = (item.failures / item.total) * 100;
139
+ if (failRate > 40) {
140
+ console.log(` โš ๏ธ [Req #${item.title}] Difficulty: ${item.diff} | Failure Rate: ${failRate.toFixed(1)}% (${item.failures}/${item.total} runs failed)`);
141
+ }
142
+ });
143
+
144
+ console.log('\n2. Strategy ROI & Dominance Check:');
145
+ allResults.forEach(res => {
146
+ console.log(` - ${res.strat.padEnd(25)}: Avg Final Capital = $${res.avgCapital.toFixed(2)} (${res.avgCapital > 0 ? 'PROFITABLE' : 'UNPROFITABLE'})`);
147
+ });